1 // SPDX-License-Identifier: GPL-2.0-only
3 * Driver for I2C connected EETI EXC3000 multiple touch controller
5 * Copyright (C) 2017 Ahmet Inan <inan@distec.de>
7 * minimal implementation based on egalax_ts.c and egalax_i2c.c
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>
19 #include <linux/timer.h>
20 #include <asm/unaligned.h>
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
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
];
37 static void exc3000_report_slots(struct input_dev
*input
,
38 struct touchscreen_properties
*prop
,
39 const u8
*buf
, int num
)
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),
53 static void exc3000_timer(struct timer_list
*t
)
55 struct exc3000_data
*data
= from_timer(data
, t
, timer
);
57 input_mt_sync_frame(data
->input
);
58 input_sync(data
->input
);
61 static int exc3000_read_frame(struct i2c_client
*client
, u8
*buf
)
65 ret
= i2c_master_send(client
, "'", 2);
72 ret
= i2c_master_recv(client
, buf
, EXC3000_LEN_FRAME
);
76 if (ret
!= EXC3000_LEN_FRAME
)
79 if (get_unaligned_le16(buf
) != EXC3000_LEN_FRAME
||
80 buf
[2] != EXC3000_MT_EVENT
)
86 static int exc3000_read_data(struct i2c_client
*client
,
87 u8
*buf
, int *n_slots
)
91 error
= exc3000_read_frame(client
, buf
);
96 if (!*n_slots
|| *n_slots
> EXC3000_NUM_SLOTS
)
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
);
105 /* 2nd chunk must have number of contacts set to 0. */
106 if (buf
[EXC3000_LEN_FRAME
+ 3] != 0)
113 static irqreturn_t
exc3000_interrupt(int irq
, void *dev_id
)
115 struct exc3000_data
*data
= dev_id
;
116 struct input_dev
*input
= data
->input
;
118 int slots
, total_slots
;
121 error
= exc3000_read_data(data
->client
, buf
, &total_slots
);
123 /* Schedule a timer to release "stuck" contacts */
124 mod_timer(&data
->timer
,
125 jiffies
+ msecs_to_jiffies(EXC3000_TIMEOUT_MS
));
130 * We read full state successfully, no contacts will be "stuck".
132 del_timer_sync(&data
->timer
);
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
;
141 input_mt_sync_frame(input
);
148 static int exc3000_probe(struct i2c_client
*client
,
149 const struct i2c_device_id
*id
)
151 struct exc3000_data
*data
;
152 struct input_dev
*input
;
155 data
= devm_kzalloc(&client
->dev
, sizeof(*data
), GFP_KERNEL
);
159 data
->client
= client
;
160 timer_setup(&data
->timer
, exc3000_timer
, 0);
162 input
= devm_input_allocate_device(&client
->dev
);
168 input
->name
= "EETI EXC3000 Touch Screen";
169 input
->id
.bustype
= BUS_I2C
;
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
);
175 error
= input_mt_init_slots(input
, EXC3000_NUM_SLOTS
,
176 INPUT_MT_DIRECT
| INPUT_MT_DROP_UNUSED
);
180 error
= input_register_device(input
);
184 error
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
185 NULL
, exc3000_interrupt
, IRQF_ONESHOT
,
193 static const struct i2c_device_id exc3000_id
[] = {
197 MODULE_DEVICE_TABLE(i2c
, exc3000_id
);
200 static const struct of_device_id exc3000_of_match
[] = {
201 { .compatible
= "eeti,exc3000" },
204 MODULE_DEVICE_TABLE(of
, exc3000_of_match
);
207 static struct i2c_driver exc3000_driver
= {
210 .of_match_table
= of_match_ptr(exc3000_of_match
),
212 .id_table
= exc3000_id
,
213 .probe
= exc3000_probe
,
216 module_i2c_driver(exc3000_driver
);
218 MODULE_AUTHOR("Ahmet Inan <inan@distec.de>");
219 MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver");
220 MODULE_LICENSE("GPL v2");