2 * Driver for I2C connected EETI EXC3000 multiple touch controller
4 * Copyright (C) 2017 Ahmet Inan <inan@distec.de>
6 * minimal implementation based on egalax_ts.c and egalax_i2c.c
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/bitops.h>
14 #include <linux/device.h>
15 #include <linux/i2c.h>
16 #include <linux/input.h>
17 #include <linux/input/mt.h>
18 #include <linux/input/touchscreen.h>
19 #include <linux/interrupt.h>
20 #include <linux/module.h>
22 #include <linux/timer.h>
23 #include <asm/unaligned.h>
25 #define EXC3000_NUM_SLOTS 10
26 #define EXC3000_SLOTS_PER_FRAME 5
27 #define EXC3000_LEN_FRAME 66
28 #define EXC3000_LEN_POINT 10
29 #define EXC3000_MT_EVENT 6
30 #define EXC3000_TIMEOUT_MS 100
33 struct i2c_client
*client
;
34 struct input_dev
*input
;
35 struct touchscreen_properties prop
;
36 struct timer_list timer
;
37 u8 buf
[2 * EXC3000_LEN_FRAME
];
40 static void exc3000_report_slots(struct input_dev
*input
,
41 struct touchscreen_properties
*prop
,
42 const u8
*buf
, int num
)
44 for (; num
--; buf
+= EXC3000_LEN_POINT
) {
45 if (buf
[0] & BIT(0)) {
46 input_mt_slot(input
, buf
[1]);
47 input_mt_report_slot_state(input
, MT_TOOL_FINGER
, true);
48 touchscreen_report_pos(input
, prop
,
49 get_unaligned_le16(buf
+ 2),
50 get_unaligned_le16(buf
+ 4),
56 static void exc3000_timer(struct timer_list
*t
)
58 struct exc3000_data
*data
= from_timer(data
, t
, timer
);
60 input_mt_sync_frame(data
->input
);
61 input_sync(data
->input
);
64 static int exc3000_read_frame(struct i2c_client
*client
, u8
*buf
)
68 ret
= i2c_master_send(client
, "'", 2);
75 ret
= i2c_master_recv(client
, buf
, EXC3000_LEN_FRAME
);
79 if (ret
!= EXC3000_LEN_FRAME
)
82 if (get_unaligned_le16(buf
) != EXC3000_LEN_FRAME
||
83 buf
[2] != EXC3000_MT_EVENT
)
89 static int exc3000_read_data(struct i2c_client
*client
,
90 u8
*buf
, int *n_slots
)
94 error
= exc3000_read_frame(client
, buf
);
99 if (!*n_slots
|| *n_slots
> EXC3000_NUM_SLOTS
)
102 if (*n_slots
> EXC3000_SLOTS_PER_FRAME
) {
103 /* Read 2nd frame to get the rest of the contacts. */
104 error
= exc3000_read_frame(client
, buf
+ EXC3000_LEN_FRAME
);
108 /* 2nd chunk must have number of contacts set to 0. */
109 if (buf
[EXC3000_LEN_FRAME
+ 3] != 0)
116 static irqreturn_t
exc3000_interrupt(int irq
, void *dev_id
)
118 struct exc3000_data
*data
= dev_id
;
119 struct input_dev
*input
= data
->input
;
121 int slots
, total_slots
;
124 error
= exc3000_read_data(data
->client
, buf
, &total_slots
);
126 /* Schedule a timer to release "stuck" contacts */
127 mod_timer(&data
->timer
,
128 jiffies
+ msecs_to_jiffies(EXC3000_TIMEOUT_MS
));
133 * We read full state successfully, no contacts will be "stuck".
135 del_timer_sync(&data
->timer
);
137 while (total_slots
> 0) {
138 slots
= min(total_slots
, EXC3000_SLOTS_PER_FRAME
);
139 exc3000_report_slots(input
, &data
->prop
, buf
+ 4, slots
);
140 total_slots
-= slots
;
141 buf
+= EXC3000_LEN_FRAME
;
144 input_mt_sync_frame(input
);
151 static int exc3000_probe(struct i2c_client
*client
,
152 const struct i2c_device_id
*id
)
154 struct exc3000_data
*data
;
155 struct input_dev
*input
;
158 data
= devm_kzalloc(&client
->dev
, sizeof(*data
), GFP_KERNEL
);
162 data
->client
= client
;
163 timer_setup(&data
->timer
, exc3000_timer
, 0);
165 input
= devm_input_allocate_device(&client
->dev
);
171 input
->name
= "EETI EXC3000 Touch Screen";
172 input
->id
.bustype
= BUS_I2C
;
174 input_set_abs_params(input
, ABS_MT_POSITION_X
, 0, 4095, 0, 0);
175 input_set_abs_params(input
, ABS_MT_POSITION_Y
, 0, 4095, 0, 0);
176 touchscreen_parse_properties(input
, true, &data
->prop
);
178 error
= input_mt_init_slots(input
, EXC3000_NUM_SLOTS
,
179 INPUT_MT_DIRECT
| INPUT_MT_DROP_UNUSED
);
183 error
= input_register_device(input
);
187 error
= devm_request_threaded_irq(&client
->dev
, client
->irq
,
188 NULL
, exc3000_interrupt
, IRQF_ONESHOT
,
196 static const struct i2c_device_id exc3000_id
[] = {
200 MODULE_DEVICE_TABLE(i2c
, exc3000_id
);
203 static const struct of_device_id exc3000_of_match
[] = {
204 { .compatible
= "eeti,exc3000" },
207 MODULE_DEVICE_TABLE(of
, exc3000_of_match
);
210 static struct i2c_driver exc3000_driver
= {
213 .of_match_table
= of_match_ptr(exc3000_of_match
),
215 .id_table
= exc3000_id
,
216 .probe
= exc3000_probe
,
219 module_i2c_driver(exc3000_driver
);
221 MODULE_AUTHOR("Ahmet Inan <inan@distec.de>");
222 MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver");
223 MODULE_LICENSE("GPL v2");