18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Touch Screen driver for SiS 9200 family I2C Touch panels 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2015 SiS, Inc. 68c2ecf20Sopenharmony_ci * Copyright (C) 2016 Nextfour Group 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/crc-itu-t.h> 108c2ecf20Sopenharmony_ci#include <linux/delay.h> 118c2ecf20Sopenharmony_ci#include <linux/i2c.h> 128c2ecf20Sopenharmony_ci#include <linux/input.h> 138c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 148c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 158c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <asm/unaligned.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define SIS_I2C_NAME "sis_i2c_ts" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci/* 238c2ecf20Sopenharmony_ci * The I2C packet format: 248c2ecf20Sopenharmony_ci * le16 byte count 258c2ecf20Sopenharmony_ci * u8 Report ID 268c2ecf20Sopenharmony_ci * <contact data - variable length> 278c2ecf20Sopenharmony_ci * u8 Number of contacts 288c2ecf20Sopenharmony_ci * le16 Scan Time (optional) 298c2ecf20Sopenharmony_ci * le16 CRC 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * One touch point information consists of 6+ bytes, the order is: 328c2ecf20Sopenharmony_ci * u8 contact state 338c2ecf20Sopenharmony_ci * u8 finger id 348c2ecf20Sopenharmony_ci * le16 x axis 358c2ecf20Sopenharmony_ci * le16 y axis 368c2ecf20Sopenharmony_ci * u8 contact width (optional) 378c2ecf20Sopenharmony_ci * u8 contact height (optional) 388c2ecf20Sopenharmony_ci * u8 pressure (optional) 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * Maximum amount of data transmitted in one shot is 64 bytes, if controller 418c2ecf20Sopenharmony_ci * needs to report more contacts than fit in one packet it will send true 428c2ecf20Sopenharmony_ci * number of contacts in first packet and 0 as number of contacts in second 438c2ecf20Sopenharmony_ci * packet. 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define SIS_MAX_PACKET_SIZE 64 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define SIS_PKT_LEN_OFFSET 0 498c2ecf20Sopenharmony_ci#define SIS_PKT_REPORT_OFFSET 2 /* Report ID/type */ 508c2ecf20Sopenharmony_ci#define SIS_PKT_CONTACT_OFFSET 3 /* First contact */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#define SIS_SCAN_TIME_LEN 2 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Supported report types */ 558c2ecf20Sopenharmony_ci#define SIS_ALL_IN_ONE_PACKAGE 0x10 568c2ecf20Sopenharmony_ci#define SIS_PKT_IS_TOUCH(x) (((x) & 0x0f) == 0x01) 578c2ecf20Sopenharmony_ci#define SIS_PKT_IS_HIDI2C(x) (((x) & 0x0f) == 0x06) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* Contact properties within report */ 608c2ecf20Sopenharmony_ci#define SIS_PKT_HAS_AREA(x) ((x) & BIT(4)) 618c2ecf20Sopenharmony_ci#define SIS_PKT_HAS_PRESSURE(x) ((x) & BIT(5)) 628c2ecf20Sopenharmony_ci#define SIS_PKT_HAS_SCANTIME(x) ((x) & BIT(6)) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci/* Contact size */ 658c2ecf20Sopenharmony_ci#define SIS_BASE_LEN_PER_CONTACT 6 668c2ecf20Sopenharmony_ci#define SIS_AREA_LEN_PER_CONTACT 2 678c2ecf20Sopenharmony_ci#define SIS_PRESSURE_LEN_PER_CONTACT 1 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* Offsets within contact data */ 708c2ecf20Sopenharmony_ci#define SIS_CONTACT_STATUS_OFFSET 0 718c2ecf20Sopenharmony_ci#define SIS_CONTACT_ID_OFFSET 1 /* Contact ID */ 728c2ecf20Sopenharmony_ci#define SIS_CONTACT_X_OFFSET 2 738c2ecf20Sopenharmony_ci#define SIS_CONTACT_Y_OFFSET 4 748c2ecf20Sopenharmony_ci#define SIS_CONTACT_WIDTH_OFFSET 6 758c2ecf20Sopenharmony_ci#define SIS_CONTACT_HEIGHT_OFFSET 7 768c2ecf20Sopenharmony_ci#define SIS_CONTACT_PRESSURE_OFFSET(id) (SIS_PKT_HAS_AREA(id) ? 8 : 6) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Individual contact state */ 798c2ecf20Sopenharmony_ci#define SIS_STATUS_UP 0x0 808c2ecf20Sopenharmony_ci#define SIS_STATUS_DOWN 0x3 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Touchscreen parameters */ 838c2ecf20Sopenharmony_ci#define SIS_MAX_FINGERS 10 848c2ecf20Sopenharmony_ci#define SIS_MAX_X 4095 858c2ecf20Sopenharmony_ci#define SIS_MAX_Y 4095 868c2ecf20Sopenharmony_ci#define SIS_MAX_PRESSURE 255 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* Resolution diagonal */ 898c2ecf20Sopenharmony_ci#define SIS_AREA_LENGTH_LONGER 5792 908c2ecf20Sopenharmony_ci/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/ 918c2ecf20Sopenharmony_ci#define SIS_AREA_LENGTH_SHORT 5792 928c2ecf20Sopenharmony_ci#define SIS_AREA_UNIT (5792 / 32) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cistruct sis_ts_data { 958c2ecf20Sopenharmony_ci struct i2c_client *client; 968c2ecf20Sopenharmony_ci struct input_dev *input; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci struct gpio_desc *attn_gpio; 998c2ecf20Sopenharmony_ci struct gpio_desc *reset_gpio; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci u8 packet[SIS_MAX_PACKET_SIZE]; 1028c2ecf20Sopenharmony_ci}; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic int sis_read_packet(struct i2c_client *client, u8 *buf, 1058c2ecf20Sopenharmony_ci unsigned int *num_contacts, 1068c2ecf20Sopenharmony_ci unsigned int *contact_size) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci int count_idx; 1098c2ecf20Sopenharmony_ci int ret; 1108c2ecf20Sopenharmony_ci u16 len; 1118c2ecf20Sopenharmony_ci u16 crc, pkg_crc; 1128c2ecf20Sopenharmony_ci u8 report_id; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE); 1158c2ecf20Sopenharmony_ci if (ret <= 0) 1168c2ecf20Sopenharmony_ci return -EIO; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]); 1198c2ecf20Sopenharmony_ci if (len > SIS_MAX_PACKET_SIZE) { 1208c2ecf20Sopenharmony_ci dev_err(&client->dev, 1218c2ecf20Sopenharmony_ci "%s: invalid packet length (%d vs %d)\n", 1228c2ecf20Sopenharmony_ci __func__, len, SIS_MAX_PACKET_SIZE); 1238c2ecf20Sopenharmony_ci return -E2BIG; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (len < 10) 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci report_id = buf[SIS_PKT_REPORT_OFFSET]; 1308c2ecf20Sopenharmony_ci count_idx = len - 1; 1318c2ecf20Sopenharmony_ci *contact_size = SIS_BASE_LEN_PER_CONTACT; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (report_id != SIS_ALL_IN_ONE_PACKAGE) { 1348c2ecf20Sopenharmony_ci if (SIS_PKT_IS_TOUCH(report_id)) { 1358c2ecf20Sopenharmony_ci /* 1368c2ecf20Sopenharmony_ci * Calculate CRC ignoring packet length 1378c2ecf20Sopenharmony_ci * in the beginning and CRC transmitted 1388c2ecf20Sopenharmony_ci * at the end of the packet. 1398c2ecf20Sopenharmony_ci */ 1408c2ecf20Sopenharmony_ci crc = crc_itu_t(0, buf + 2, len - 2 - 2); 1418c2ecf20Sopenharmony_ci pkg_crc = get_unaligned_le16(&buf[len - 2]); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci if (crc != pkg_crc) { 1448c2ecf20Sopenharmony_ci dev_err(&client->dev, 1458c2ecf20Sopenharmony_ci "%s: CRC Error (%d vs %d)\n", 1468c2ecf20Sopenharmony_ci __func__, crc, pkg_crc); 1478c2ecf20Sopenharmony_ci return -EINVAL; 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci count_idx -= 2; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci } else if (!SIS_PKT_IS_HIDI2C(report_id)) { 1538c2ecf20Sopenharmony_ci dev_err(&client->dev, 1548c2ecf20Sopenharmony_ci "%s: invalid packet ID %#02x\n", 1558c2ecf20Sopenharmony_ci __func__, report_id); 1568c2ecf20Sopenharmony_ci return -EINVAL; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (SIS_PKT_HAS_SCANTIME(report_id)) 1608c2ecf20Sopenharmony_ci count_idx -= SIS_SCAN_TIME_LEN; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (SIS_PKT_HAS_AREA(report_id)) 1638c2ecf20Sopenharmony_ci *contact_size += SIS_AREA_LEN_PER_CONTACT; 1648c2ecf20Sopenharmony_ci if (SIS_PKT_HAS_PRESSURE(report_id)) 1658c2ecf20Sopenharmony_ci *contact_size += SIS_PRESSURE_LEN_PER_CONTACT; 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci *num_contacts = buf[count_idx]; 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci struct input_dev *input = ts->input; 1758c2ecf20Sopenharmony_ci int slot; 1768c2ecf20Sopenharmony_ci u8 status = data[SIS_CONTACT_STATUS_OFFSET]; 1778c2ecf20Sopenharmony_ci u8 pressure; 1788c2ecf20Sopenharmony_ci u8 height, width; 1798c2ecf20Sopenharmony_ci u16 x, y; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) { 1828c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n", 1838c2ecf20Sopenharmony_ci data[SIS_CONTACT_STATUS_OFFSET]); 1848c2ecf20Sopenharmony_ci return -EINVAL; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]); 1888c2ecf20Sopenharmony_ci if (slot < 0) 1898c2ecf20Sopenharmony_ci return -ENOENT; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci input_mt_slot(input, slot); 1928c2ecf20Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, 1938c2ecf20Sopenharmony_ci status == SIS_STATUS_DOWN); 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (status == SIS_STATUS_DOWN) { 1968c2ecf20Sopenharmony_ci pressure = height = width = 1; 1978c2ecf20Sopenharmony_ci if (id != SIS_ALL_IN_ONE_PACKAGE) { 1988c2ecf20Sopenharmony_ci if (SIS_PKT_HAS_AREA(id)) { 1998c2ecf20Sopenharmony_ci width = data[SIS_CONTACT_WIDTH_OFFSET]; 2008c2ecf20Sopenharmony_ci height = data[SIS_CONTACT_HEIGHT_OFFSET]; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (SIS_PKT_HAS_PRESSURE(id)) 2048c2ecf20Sopenharmony_ci pressure = 2058c2ecf20Sopenharmony_ci data[SIS_CONTACT_PRESSURE_OFFSET(id)]; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]); 2098c2ecf20Sopenharmony_ci y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_TOUCH_MAJOR, 2128c2ecf20Sopenharmony_ci width * SIS_AREA_UNIT); 2138c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_TOUCH_MINOR, 2148c2ecf20Sopenharmony_ci height * SIS_AREA_UNIT); 2158c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_PRESSURE, pressure); 2168c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_X, x); 2178c2ecf20Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_Y, y); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return 0; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void sis_ts_handle_packet(struct sis_ts_data *ts) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci const u8 *contact; 2268c2ecf20Sopenharmony_ci unsigned int num_to_report = 0; 2278c2ecf20Sopenharmony_ci unsigned int num_contacts; 2288c2ecf20Sopenharmony_ci unsigned int num_reported; 2298c2ecf20Sopenharmony_ci unsigned int contact_size; 2308c2ecf20Sopenharmony_ci int error; 2318c2ecf20Sopenharmony_ci u8 report_id; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci do { 2348c2ecf20Sopenharmony_ci error = sis_read_packet(ts->client, ts->packet, 2358c2ecf20Sopenharmony_ci &num_contacts, &contact_size); 2368c2ecf20Sopenharmony_ci if (error) 2378c2ecf20Sopenharmony_ci break; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci if (num_to_report == 0) { 2408c2ecf20Sopenharmony_ci num_to_report = num_contacts; 2418c2ecf20Sopenharmony_ci } else if (num_contacts != 0) { 2428c2ecf20Sopenharmony_ci dev_err(&ts->client->dev, 2438c2ecf20Sopenharmony_ci "%s: nonzero (%d) point count in tail packet\n", 2448c2ecf20Sopenharmony_ci __func__, num_contacts); 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci report_id = ts->packet[SIS_PKT_REPORT_OFFSET]; 2498c2ecf20Sopenharmony_ci contact = &ts->packet[SIS_PKT_CONTACT_OFFSET]; 2508c2ecf20Sopenharmony_ci num_reported = 0; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci while (num_to_report > 0) { 2538c2ecf20Sopenharmony_ci error = sis_ts_report_contact(ts, contact, report_id); 2548c2ecf20Sopenharmony_ci if (error) 2558c2ecf20Sopenharmony_ci break; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci contact += contact_size; 2588c2ecf20Sopenharmony_ci num_to_report--; 2598c2ecf20Sopenharmony_ci num_reported++; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (report_id != SIS_ALL_IN_ONE_PACKAGE && 2628c2ecf20Sopenharmony_ci num_reported >= 5) { 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * The remainder of contacts is sent 2658c2ecf20Sopenharmony_ci * in the 2nd packet. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci } while (num_to_report > 0); 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci input_mt_sync_frame(ts->input); 2738c2ecf20Sopenharmony_ci input_sync(ts->input); 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic irqreturn_t sis_ts_irq_handler(int irq, void *dev_id) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct sis_ts_data *ts = dev_id; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci do { 2818c2ecf20Sopenharmony_ci sis_ts_handle_packet(ts); 2828c2ecf20Sopenharmony_ci } while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio)); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return IRQ_HANDLED; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void sis_ts_reset(struct sis_ts_data *ts) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci if (ts->reset_gpio) { 2908c2ecf20Sopenharmony_ci /* Get out of reset */ 2918c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 2928c2ecf20Sopenharmony_ci gpiod_set_value(ts->reset_gpio, 1); 2938c2ecf20Sopenharmony_ci usleep_range(1000, 2000); 2948c2ecf20Sopenharmony_ci gpiod_set_value(ts->reset_gpio, 0); 2958c2ecf20Sopenharmony_ci msleep(100); 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic int sis_ts_probe(struct i2c_client *client, 3008c2ecf20Sopenharmony_ci const struct i2c_device_id *id) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci struct sis_ts_data *ts; 3038c2ecf20Sopenharmony_ci struct input_dev *input; 3048c2ecf20Sopenharmony_ci int error; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 3078c2ecf20Sopenharmony_ci if (!ts) 3088c2ecf20Sopenharmony_ci return -ENOMEM; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci ts->client = client; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci ts->attn_gpio = devm_gpiod_get_optional(&client->dev, 3138c2ecf20Sopenharmony_ci "attn", GPIOD_IN); 3148c2ecf20Sopenharmony_ci if (IS_ERR(ts->attn_gpio)) { 3158c2ecf20Sopenharmony_ci error = PTR_ERR(ts->attn_gpio); 3168c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 3178c2ecf20Sopenharmony_ci dev_err(&client->dev, 3188c2ecf20Sopenharmony_ci "Failed to get attention GPIO: %d\n", error); 3198c2ecf20Sopenharmony_ci return error; 3208c2ecf20Sopenharmony_ci } 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci ts->reset_gpio = devm_gpiod_get_optional(&client->dev, 3238c2ecf20Sopenharmony_ci "reset", GPIOD_OUT_LOW); 3248c2ecf20Sopenharmony_ci if (IS_ERR(ts->reset_gpio)) { 3258c2ecf20Sopenharmony_ci error = PTR_ERR(ts->reset_gpio); 3268c2ecf20Sopenharmony_ci if (error != -EPROBE_DEFER) 3278c2ecf20Sopenharmony_ci dev_err(&client->dev, 3288c2ecf20Sopenharmony_ci "Failed to get reset GPIO: %d\n", error); 3298c2ecf20Sopenharmony_ci return error; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci sis_ts_reset(ts); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ts->input = input = devm_input_allocate_device(&client->dev); 3358c2ecf20Sopenharmony_ci if (!input) { 3368c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to allocate input device\n"); 3378c2ecf20Sopenharmony_ci return -ENOMEM; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci input->name = "SiS Touchscreen"; 3418c2ecf20Sopenharmony_ci input->id.bustype = BUS_I2C; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0); 3448c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0); 3458c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0); 3468c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 3478c2ecf20Sopenharmony_ci 0, SIS_AREA_LENGTH_LONGER, 0, 0); 3488c2ecf20Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 3498c2ecf20Sopenharmony_ci 0, SIS_AREA_LENGTH_SHORT, 0, 0); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT); 3528c2ecf20Sopenharmony_ci if (error) { 3538c2ecf20Sopenharmony_ci dev_err(&client->dev, 3548c2ecf20Sopenharmony_ci "Failed to initialize MT slots: %d\n", error); 3558c2ecf20Sopenharmony_ci return error; 3568c2ecf20Sopenharmony_ci } 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 3598c2ecf20Sopenharmony_ci NULL, sis_ts_irq_handler, 3608c2ecf20Sopenharmony_ci IRQF_ONESHOT, 3618c2ecf20Sopenharmony_ci client->name, ts); 3628c2ecf20Sopenharmony_ci if (error) { 3638c2ecf20Sopenharmony_ci dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 3648c2ecf20Sopenharmony_ci return error; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci error = input_register_device(ts->input); 3688c2ecf20Sopenharmony_ci if (error) { 3698c2ecf20Sopenharmony_ci dev_err(&client->dev, 3708c2ecf20Sopenharmony_ci "Failed to register input device: %d\n", error); 3718c2ecf20Sopenharmony_ci return error; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci return 0; 3758c2ecf20Sopenharmony_ci} 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 3788c2ecf20Sopenharmony_cistatic const struct of_device_id sis_ts_dt_ids[] = { 3798c2ecf20Sopenharmony_ci { .compatible = "sis,9200-ts" }, 3808c2ecf20Sopenharmony_ci { /* sentinel */ } 3818c2ecf20Sopenharmony_ci}; 3828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sis_ts_dt_ids); 3838c2ecf20Sopenharmony_ci#endif 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic const struct i2c_device_id sis_ts_id[] = { 3868c2ecf20Sopenharmony_ci { SIS_I2C_NAME, 0 }, 3878c2ecf20Sopenharmony_ci { "9200-ts", 0 }, 3888c2ecf20Sopenharmony_ci { /* sentinel */ } 3898c2ecf20Sopenharmony_ci}; 3908c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sis_ts_id); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic struct i2c_driver sis_ts_driver = { 3938c2ecf20Sopenharmony_ci .driver = { 3948c2ecf20Sopenharmony_ci .name = SIS_I2C_NAME, 3958c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(sis_ts_dt_ids), 3968c2ecf20Sopenharmony_ci }, 3978c2ecf20Sopenharmony_ci .probe = sis_ts_probe, 3988c2ecf20Sopenharmony_ci .id_table = sis_ts_id, 3998c2ecf20Sopenharmony_ci}; 4008c2ecf20Sopenharmony_cimodule_i2c_driver(sis_ts_driver); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver"); 4038c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 4048c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>"); 405