162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Touch Screen driver for SiS 9200 family I2C Touch panels 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 SiS, Inc. 662306a36Sopenharmony_ci * Copyright (C) 2016 Nextfour Group 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/crc-itu-t.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/input.h> 1362306a36Sopenharmony_ci#include <linux/input/mt.h> 1462306a36Sopenharmony_ci#include <linux/interrupt.h> 1562306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <asm/unaligned.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#define SIS_I2C_NAME "sis_i2c_ts" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci/* 2362306a36Sopenharmony_ci * The I2C packet format: 2462306a36Sopenharmony_ci * le16 byte count 2562306a36Sopenharmony_ci * u8 Report ID 2662306a36Sopenharmony_ci * <contact data - variable length> 2762306a36Sopenharmony_ci * u8 Number of contacts 2862306a36Sopenharmony_ci * le16 Scan Time (optional) 2962306a36Sopenharmony_ci * le16 CRC 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * One touch point information consists of 6+ bytes, the order is: 3262306a36Sopenharmony_ci * u8 contact state 3362306a36Sopenharmony_ci * u8 finger id 3462306a36Sopenharmony_ci * le16 x axis 3562306a36Sopenharmony_ci * le16 y axis 3662306a36Sopenharmony_ci * u8 contact width (optional) 3762306a36Sopenharmony_ci * u8 contact height (optional) 3862306a36Sopenharmony_ci * u8 pressure (optional) 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Maximum amount of data transmitted in one shot is 64 bytes, if controller 4162306a36Sopenharmony_ci * needs to report more contacts than fit in one packet it will send true 4262306a36Sopenharmony_ci * number of contacts in first packet and 0 as number of contacts in second 4362306a36Sopenharmony_ci * packet. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define SIS_MAX_PACKET_SIZE 64 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define SIS_PKT_LEN_OFFSET 0 4962306a36Sopenharmony_ci#define SIS_PKT_REPORT_OFFSET 2 /* Report ID/type */ 5062306a36Sopenharmony_ci#define SIS_PKT_CONTACT_OFFSET 3 /* First contact */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define SIS_SCAN_TIME_LEN 2 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* Supported report types */ 5562306a36Sopenharmony_ci#define SIS_ALL_IN_ONE_PACKAGE 0x10 5662306a36Sopenharmony_ci#define SIS_PKT_IS_TOUCH(x) (((x) & 0x0f) == 0x01) 5762306a36Sopenharmony_ci#define SIS_PKT_IS_HIDI2C(x) (((x) & 0x0f) == 0x06) 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* Contact properties within report */ 6062306a36Sopenharmony_ci#define SIS_PKT_HAS_AREA(x) ((x) & BIT(4)) 6162306a36Sopenharmony_ci#define SIS_PKT_HAS_PRESSURE(x) ((x) & BIT(5)) 6262306a36Sopenharmony_ci#define SIS_PKT_HAS_SCANTIME(x) ((x) & BIT(6)) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Contact size */ 6562306a36Sopenharmony_ci#define SIS_BASE_LEN_PER_CONTACT 6 6662306a36Sopenharmony_ci#define SIS_AREA_LEN_PER_CONTACT 2 6762306a36Sopenharmony_ci#define SIS_PRESSURE_LEN_PER_CONTACT 1 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* Offsets within contact data */ 7062306a36Sopenharmony_ci#define SIS_CONTACT_STATUS_OFFSET 0 7162306a36Sopenharmony_ci#define SIS_CONTACT_ID_OFFSET 1 /* Contact ID */ 7262306a36Sopenharmony_ci#define SIS_CONTACT_X_OFFSET 2 7362306a36Sopenharmony_ci#define SIS_CONTACT_Y_OFFSET 4 7462306a36Sopenharmony_ci#define SIS_CONTACT_WIDTH_OFFSET 6 7562306a36Sopenharmony_ci#define SIS_CONTACT_HEIGHT_OFFSET 7 7662306a36Sopenharmony_ci#define SIS_CONTACT_PRESSURE_OFFSET(id) (SIS_PKT_HAS_AREA(id) ? 8 : 6) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/* Individual contact state */ 7962306a36Sopenharmony_ci#define SIS_STATUS_UP 0x0 8062306a36Sopenharmony_ci#define SIS_STATUS_DOWN 0x3 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* Touchscreen parameters */ 8362306a36Sopenharmony_ci#define SIS_MAX_FINGERS 10 8462306a36Sopenharmony_ci#define SIS_MAX_X 4095 8562306a36Sopenharmony_ci#define SIS_MAX_Y 4095 8662306a36Sopenharmony_ci#define SIS_MAX_PRESSURE 255 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci/* Resolution diagonal */ 8962306a36Sopenharmony_ci#define SIS_AREA_LENGTH_LONGER 5792 9062306a36Sopenharmony_ci/*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/ 9162306a36Sopenharmony_ci#define SIS_AREA_LENGTH_SHORT 5792 9262306a36Sopenharmony_ci#define SIS_AREA_UNIT (5792 / 32) 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistruct sis_ts_data { 9562306a36Sopenharmony_ci struct i2c_client *client; 9662306a36Sopenharmony_ci struct input_dev *input; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci struct gpio_desc *attn_gpio; 9962306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci u8 packet[SIS_MAX_PACKET_SIZE]; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int sis_read_packet(struct i2c_client *client, u8 *buf, 10562306a36Sopenharmony_ci unsigned int *num_contacts, 10662306a36Sopenharmony_ci unsigned int *contact_size) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci int count_idx; 10962306a36Sopenharmony_ci int ret; 11062306a36Sopenharmony_ci u16 len; 11162306a36Sopenharmony_ci u16 crc, pkg_crc; 11262306a36Sopenharmony_ci u8 report_id; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE); 11562306a36Sopenharmony_ci if (ret <= 0) 11662306a36Sopenharmony_ci return -EIO; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]); 11962306a36Sopenharmony_ci if (len > SIS_MAX_PACKET_SIZE) { 12062306a36Sopenharmony_ci dev_err(&client->dev, 12162306a36Sopenharmony_ci "%s: invalid packet length (%d vs %d)\n", 12262306a36Sopenharmony_ci __func__, len, SIS_MAX_PACKET_SIZE); 12362306a36Sopenharmony_ci return -E2BIG; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (len < 10) 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci report_id = buf[SIS_PKT_REPORT_OFFSET]; 13062306a36Sopenharmony_ci count_idx = len - 1; 13162306a36Sopenharmony_ci *contact_size = SIS_BASE_LEN_PER_CONTACT; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (report_id != SIS_ALL_IN_ONE_PACKAGE) { 13462306a36Sopenharmony_ci if (SIS_PKT_IS_TOUCH(report_id)) { 13562306a36Sopenharmony_ci /* 13662306a36Sopenharmony_ci * Calculate CRC ignoring packet length 13762306a36Sopenharmony_ci * in the beginning and CRC transmitted 13862306a36Sopenharmony_ci * at the end of the packet. 13962306a36Sopenharmony_ci */ 14062306a36Sopenharmony_ci crc = crc_itu_t(0, buf + 2, len - 2 - 2); 14162306a36Sopenharmony_ci pkg_crc = get_unaligned_le16(&buf[len - 2]); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (crc != pkg_crc) { 14462306a36Sopenharmony_ci dev_err(&client->dev, 14562306a36Sopenharmony_ci "%s: CRC Error (%d vs %d)\n", 14662306a36Sopenharmony_ci __func__, crc, pkg_crc); 14762306a36Sopenharmony_ci return -EINVAL; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci count_idx -= 2; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci } else if (!SIS_PKT_IS_HIDI2C(report_id)) { 15362306a36Sopenharmony_ci dev_err(&client->dev, 15462306a36Sopenharmony_ci "%s: invalid packet ID %#02x\n", 15562306a36Sopenharmony_ci __func__, report_id); 15662306a36Sopenharmony_ci return -EINVAL; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci if (SIS_PKT_HAS_SCANTIME(report_id)) 16062306a36Sopenharmony_ci count_idx -= SIS_SCAN_TIME_LEN; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci if (SIS_PKT_HAS_AREA(report_id)) 16362306a36Sopenharmony_ci *contact_size += SIS_AREA_LEN_PER_CONTACT; 16462306a36Sopenharmony_ci if (SIS_PKT_HAS_PRESSURE(report_id)) 16562306a36Sopenharmony_ci *contact_size += SIS_PRESSURE_LEN_PER_CONTACT; 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci *num_contacts = buf[count_idx]; 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct input_dev *input = ts->input; 17562306a36Sopenharmony_ci int slot; 17662306a36Sopenharmony_ci u8 status = data[SIS_CONTACT_STATUS_OFFSET]; 17762306a36Sopenharmony_ci u8 pressure; 17862306a36Sopenharmony_ci u8 height, width; 17962306a36Sopenharmony_ci u16 x, y; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) { 18262306a36Sopenharmony_ci dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n", 18362306a36Sopenharmony_ci data[SIS_CONTACT_STATUS_OFFSET]); 18462306a36Sopenharmony_ci return -EINVAL; 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]); 18862306a36Sopenharmony_ci if (slot < 0) 18962306a36Sopenharmony_ci return -ENOENT; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci input_mt_slot(input, slot); 19262306a36Sopenharmony_ci input_mt_report_slot_state(input, MT_TOOL_FINGER, 19362306a36Sopenharmony_ci status == SIS_STATUS_DOWN); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci if (status == SIS_STATUS_DOWN) { 19662306a36Sopenharmony_ci pressure = height = width = 1; 19762306a36Sopenharmony_ci if (id != SIS_ALL_IN_ONE_PACKAGE) { 19862306a36Sopenharmony_ci if (SIS_PKT_HAS_AREA(id)) { 19962306a36Sopenharmony_ci width = data[SIS_CONTACT_WIDTH_OFFSET]; 20062306a36Sopenharmony_ci height = data[SIS_CONTACT_HEIGHT_OFFSET]; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (SIS_PKT_HAS_PRESSURE(id)) 20462306a36Sopenharmony_ci pressure = 20562306a36Sopenharmony_ci data[SIS_CONTACT_PRESSURE_OFFSET(id)]; 20662306a36Sopenharmony_ci } 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]); 20962306a36Sopenharmony_ci y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]); 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci input_report_abs(input, ABS_MT_TOUCH_MAJOR, 21262306a36Sopenharmony_ci width * SIS_AREA_UNIT); 21362306a36Sopenharmony_ci input_report_abs(input, ABS_MT_TOUCH_MINOR, 21462306a36Sopenharmony_ci height * SIS_AREA_UNIT); 21562306a36Sopenharmony_ci input_report_abs(input, ABS_MT_PRESSURE, pressure); 21662306a36Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_X, x); 21762306a36Sopenharmony_ci input_report_abs(input, ABS_MT_POSITION_Y, y); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void sis_ts_handle_packet(struct sis_ts_data *ts) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci const u8 *contact; 22662306a36Sopenharmony_ci unsigned int num_to_report = 0; 22762306a36Sopenharmony_ci unsigned int num_contacts; 22862306a36Sopenharmony_ci unsigned int num_reported; 22962306a36Sopenharmony_ci unsigned int contact_size; 23062306a36Sopenharmony_ci int error; 23162306a36Sopenharmony_ci u8 report_id; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci do { 23462306a36Sopenharmony_ci error = sis_read_packet(ts->client, ts->packet, 23562306a36Sopenharmony_ci &num_contacts, &contact_size); 23662306a36Sopenharmony_ci if (error) 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (num_to_report == 0) { 24062306a36Sopenharmony_ci num_to_report = num_contacts; 24162306a36Sopenharmony_ci } else if (num_contacts != 0) { 24262306a36Sopenharmony_ci dev_err(&ts->client->dev, 24362306a36Sopenharmony_ci "%s: nonzero (%d) point count in tail packet\n", 24462306a36Sopenharmony_ci __func__, num_contacts); 24562306a36Sopenharmony_ci break; 24662306a36Sopenharmony_ci } 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci report_id = ts->packet[SIS_PKT_REPORT_OFFSET]; 24962306a36Sopenharmony_ci contact = &ts->packet[SIS_PKT_CONTACT_OFFSET]; 25062306a36Sopenharmony_ci num_reported = 0; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci while (num_to_report > 0) { 25362306a36Sopenharmony_ci error = sis_ts_report_contact(ts, contact, report_id); 25462306a36Sopenharmony_ci if (error) 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci contact += contact_size; 25862306a36Sopenharmony_ci num_to_report--; 25962306a36Sopenharmony_ci num_reported++; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (report_id != SIS_ALL_IN_ONE_PACKAGE && 26262306a36Sopenharmony_ci num_reported >= 5) { 26362306a36Sopenharmony_ci /* 26462306a36Sopenharmony_ci * The remainder of contacts is sent 26562306a36Sopenharmony_ci * in the 2nd packet. 26662306a36Sopenharmony_ci */ 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci } while (num_to_report > 0); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci input_mt_sync_frame(ts->input); 27362306a36Sopenharmony_ci input_sync(ts->input); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic irqreturn_t sis_ts_irq_handler(int irq, void *dev_id) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct sis_ts_data *ts = dev_id; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci do { 28162306a36Sopenharmony_ci sis_ts_handle_packet(ts); 28262306a36Sopenharmony_ci } while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio)); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci return IRQ_HANDLED; 28562306a36Sopenharmony_ci} 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_cistatic void sis_ts_reset(struct sis_ts_data *ts) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci if (ts->reset_gpio) { 29062306a36Sopenharmony_ci /* Get out of reset */ 29162306a36Sopenharmony_ci usleep_range(1000, 2000); 29262306a36Sopenharmony_ci gpiod_set_value(ts->reset_gpio, 1); 29362306a36Sopenharmony_ci usleep_range(1000, 2000); 29462306a36Sopenharmony_ci gpiod_set_value(ts->reset_gpio, 0); 29562306a36Sopenharmony_ci msleep(100); 29662306a36Sopenharmony_ci } 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int sis_ts_probe(struct i2c_client *client) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct sis_ts_data *ts; 30262306a36Sopenharmony_ci struct input_dev *input; 30362306a36Sopenharmony_ci int error; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); 30662306a36Sopenharmony_ci if (!ts) 30762306a36Sopenharmony_ci return -ENOMEM; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci ts->client = client; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci ts->attn_gpio = devm_gpiod_get_optional(&client->dev, 31262306a36Sopenharmony_ci "attn", GPIOD_IN); 31362306a36Sopenharmony_ci if (IS_ERR(ts->attn_gpio)) 31462306a36Sopenharmony_ci return dev_err_probe(&client->dev, PTR_ERR(ts->attn_gpio), 31562306a36Sopenharmony_ci "Failed to get attention GPIO\n"); 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci ts->reset_gpio = devm_gpiod_get_optional(&client->dev, 31862306a36Sopenharmony_ci "reset", GPIOD_OUT_LOW); 31962306a36Sopenharmony_ci if (IS_ERR(ts->reset_gpio)) 32062306a36Sopenharmony_ci return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio), 32162306a36Sopenharmony_ci "Failed to get reset GPIO\n"); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci sis_ts_reset(ts); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci ts->input = input = devm_input_allocate_device(&client->dev); 32662306a36Sopenharmony_ci if (!input) { 32762306a36Sopenharmony_ci dev_err(&client->dev, "Failed to allocate input device\n"); 32862306a36Sopenharmony_ci return -ENOMEM; 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci input->name = "SiS Touchscreen"; 33262306a36Sopenharmony_ci input->id.bustype = BUS_I2C; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0); 33562306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0); 33662306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0); 33762306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 33862306a36Sopenharmony_ci 0, SIS_AREA_LENGTH_LONGER, 0, 0); 33962306a36Sopenharmony_ci input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 34062306a36Sopenharmony_ci 0, SIS_AREA_LENGTH_SHORT, 0, 0); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT); 34362306a36Sopenharmony_ci if (error) { 34462306a36Sopenharmony_ci dev_err(&client->dev, 34562306a36Sopenharmony_ci "Failed to initialize MT slots: %d\n", error); 34662306a36Sopenharmony_ci return error; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci error = devm_request_threaded_irq(&client->dev, client->irq, 35062306a36Sopenharmony_ci NULL, sis_ts_irq_handler, 35162306a36Sopenharmony_ci IRQF_ONESHOT, 35262306a36Sopenharmony_ci client->name, ts); 35362306a36Sopenharmony_ci if (error) { 35462306a36Sopenharmony_ci dev_err(&client->dev, "Failed to request IRQ: %d\n", error); 35562306a36Sopenharmony_ci return error; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci error = input_register_device(ts->input); 35962306a36Sopenharmony_ci if (error) { 36062306a36Sopenharmony_ci dev_err(&client->dev, 36162306a36Sopenharmony_ci "Failed to register input device: %d\n", error); 36262306a36Sopenharmony_ci return error; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return 0; 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci#ifdef CONFIG_OF 36962306a36Sopenharmony_cistatic const struct of_device_id sis_ts_dt_ids[] = { 37062306a36Sopenharmony_ci { .compatible = "sis,9200-ts" }, 37162306a36Sopenharmony_ci { /* sentinel */ } 37262306a36Sopenharmony_ci}; 37362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sis_ts_dt_ids); 37462306a36Sopenharmony_ci#endif 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic const struct i2c_device_id sis_ts_id[] = { 37762306a36Sopenharmony_ci { SIS_I2C_NAME, 0 }, 37862306a36Sopenharmony_ci { "9200-ts", 0 }, 37962306a36Sopenharmony_ci { /* sentinel */ } 38062306a36Sopenharmony_ci}; 38162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, sis_ts_id); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic struct i2c_driver sis_ts_driver = { 38462306a36Sopenharmony_ci .driver = { 38562306a36Sopenharmony_ci .name = SIS_I2C_NAME, 38662306a36Sopenharmony_ci .of_match_table = of_match_ptr(sis_ts_dt_ids), 38762306a36Sopenharmony_ci }, 38862306a36Sopenharmony_ci .probe = sis_ts_probe, 38962306a36Sopenharmony_ci .id_table = sis_ts_id, 39062306a36Sopenharmony_ci}; 39162306a36Sopenharmony_cimodule_i2c_driver(sis_ts_driver); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ciMODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver"); 39462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 39562306a36Sopenharmony_ciMODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>"); 396