1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Driver for I2C connected EETI EXC3000 multiple touch controller 4 * 5 * Copyright (C) 2017 Ahmet Inan <inan@distec.de> 6 * 7 * minimal implementation based on egalax_ts.c and egalax_i2c.c 8 */ 9 10 #include <linux/bitops.h> 11 #include <linux/device.h> 12 #include <linux/i2c.h> 13 #include <linux/input.h> 14 #include <linux/input/mt.h> 15 #include <linux/input/touchscreen.h> 16 #include <linux/interrupt.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/timer.h> 20 #include <asm/unaligned.h> 21 22 #define EXC3000_NUM_SLOTS 10 23 #define EXC3000_SLOTS_PER_FRAME 5 24 #define EXC3000_LEN_FRAME 66 25 #define EXC3000_LEN_POINT 10 26 #define EXC3000_MT_EVENT 6 27 #define EXC3000_TIMEOUT_MS 100 28 29 struct exc3000_data { 30 struct i2c_client *client; 31 struct input_dev *input; 32 struct touchscreen_properties prop; 33 struct timer_list timer; 34 u8 buf[2 * EXC3000_LEN_FRAME]; 35 }; 36 37 static void exc3000_report_slots(struct input_dev *input, 38 struct touchscreen_properties *prop, 39 const u8 *buf, int num) 40 { 41 for (; num--; buf += EXC3000_LEN_POINT) { 42 if (buf[0] & BIT(0)) { 43 input_mt_slot(input, buf[1]); 44 input_mt_report_slot_state(input, MT_TOOL_FINGER, true); 45 touchscreen_report_pos(input, prop, 46 get_unaligned_le16(buf + 2), 47 get_unaligned_le16(buf + 4), 48 true); 49 } 50 } 51 } 52 53 static void exc3000_timer(struct timer_list *t) 54 { 55 struct exc3000_data *data = from_timer(data, t, timer); 56 57 input_mt_sync_frame(data->input); 58 input_sync(data->input); 59 } 60 61 static int exc3000_read_frame(struct i2c_client *client, u8 *buf) 62 { 63 int ret; 64 65 ret = i2c_master_send(client, "'", 2); 66 if (ret < 0) 67 return ret; 68 69 if (ret != 2) 70 return -EIO; 71 72 ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME); 73 if (ret < 0) 74 return ret; 75 76 if (ret != EXC3000_LEN_FRAME) 77 return -EIO; 78 79 if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME || 80 buf[2] != EXC3000_MT_EVENT) 81 return -EINVAL; 82 83 return 0; 84 } 85 86 static int exc3000_read_data(struct i2c_client *client, 87 u8 *buf, int *n_slots) 88 { 89 int error; 90 91 error = exc3000_read_frame(client, buf); 92 if (error) 93 return error; 94 95 *n_slots = buf[3]; 96 if (!*n_slots || *n_slots > EXC3000_NUM_SLOTS) 97 return -EINVAL; 98 99 if (*n_slots > EXC3000_SLOTS_PER_FRAME) { 100 /* Read 2nd frame to get the rest of the contacts. */ 101 error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME); 102 if (error) 103 return error; 104 105 /* 2nd chunk must have number of contacts set to 0. */ 106 if (buf[EXC3000_LEN_FRAME + 3] != 0) 107 return -EINVAL; 108 } 109 110 return 0; 111 } 112 113 static irqreturn_t exc3000_interrupt(int irq, void *dev_id) 114 { 115 struct exc3000_data *data = dev_id; 116 struct input_dev *input = data->input; 117 u8 *buf = data->buf; 118 int slots, total_slots; 119 int error; 120 121 error = exc3000_read_data(data->client, buf, &total_slots); 122 if (error) { 123 /* Schedule a timer to release "stuck" contacts */ 124 mod_timer(&data->timer, 125 jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS)); 126 goto out; 127 } 128 129 /* 130 * We read full state successfully, no contacts will be "stuck". 131 */ 132 del_timer_sync(&data->timer); 133 134 while (total_slots > 0) { 135 slots = min(total_slots, EXC3000_SLOTS_PER_FRAME); 136 exc3000_report_slots(input, &data->prop, buf + 4, slots); 137 total_slots -= slots; 138 buf += EXC3000_LEN_FRAME; 139 } 140 141 input_mt_sync_frame(input); 142 input_sync(input); 143 144 out: 145 return IRQ_HANDLED; 146 } 147 148 static int exc3000_probe(struct i2c_client *client, 149 const struct i2c_device_id *id) 150 { 151 struct exc3000_data *data; 152 struct input_dev *input; 153 int error; 154 155 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 156 if (!data) 157 return -ENOMEM; 158 159 data->client = client; 160 timer_setup(&data->timer, exc3000_timer, 0); 161 162 input = devm_input_allocate_device(&client->dev); 163 if (!input) 164 return -ENOMEM; 165 166 data->input = input; 167 168 input->name = "EETI EXC3000 Touch Screen"; 169 input->id.bustype = BUS_I2C; 170 171 input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0); 172 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0); 173 touchscreen_parse_properties(input, true, &data->prop); 174 175 error = input_mt_init_slots(input, EXC3000_NUM_SLOTS, 176 INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); 177 if (error) 178 return error; 179 180 error = input_register_device(input); 181 if (error) 182 return error; 183 184 error = devm_request_threaded_irq(&client->dev, client->irq, 185 NULL, exc3000_interrupt, IRQF_ONESHOT, 186 client->name, data); 187 if (error) 188 return error; 189 190 return 0; 191 } 192 193 static const struct i2c_device_id exc3000_id[] = { 194 { "exc3000", 0 }, 195 { } 196 }; 197 MODULE_DEVICE_TABLE(i2c, exc3000_id); 198 199 #ifdef CONFIG_OF 200 static const struct of_device_id exc3000_of_match[] = { 201 { .compatible = "eeti,exc3000" }, 202 { } 203 }; 204 MODULE_DEVICE_TABLE(of, exc3000_of_match); 205 #endif 206 207 static struct i2c_driver exc3000_driver = { 208 .driver = { 209 .name = "exc3000", 210 .of_match_table = of_match_ptr(exc3000_of_match), 211 }, 212 .id_table = exc3000_id, 213 .probe = exc3000_probe, 214 }; 215 216 module_i2c_driver(exc3000_driver); 217 218 MODULE_AUTHOR("Ahmet Inan <inan@distec.de>"); 219 MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver"); 220 MODULE_LICENSE("GPL v2"); 221