1 // SPDX-License-Identifier: GPL-2.0-only
3 * TSC-40 serial touchscreen driver. It should be compatible with
6 * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/input.h>
13 #include <linux/serio.h>
15 #define PACKET_LENGTH 5
17 struct input_dev
*dev
;
20 unsigned char data
[PACKET_LENGTH
];
24 static void tsc_process_data(struct tsc_ser
*ptsc
)
26 struct input_dev
*dev
= ptsc
->dev
;
27 u8
*data
= ptsc
->data
;
31 x
= ((data
[1] & 0x03) << 8) | data
[2];
32 y
= ((data
[3] & 0x03) << 8) | data
[4];
34 input_report_abs(dev
, ABS_X
, x
);
35 input_report_abs(dev
, ABS_Y
, y
);
36 input_report_key(dev
, BTN_TOUCH
, 1);
41 static irqreturn_t
tsc_interrupt(struct serio
*serio
,
42 unsigned char data
, unsigned int flags
)
44 struct tsc_ser
*ptsc
= serio_get_drvdata(serio
);
45 struct input_dev
*dev
= ptsc
->dev
;
47 ptsc
->data
[ptsc
->idx
] = data
;
48 switch (ptsc
->idx
++) {
50 if (unlikely((data
& 0x3e) != 0x10)) {
52 "unsynchronized packet start (0x%02x)\n", data
);
54 } else if (!(data
& 0x01)) {
55 input_report_key(dev
, BTN_TOUCH
, 0);
63 if (unlikely(data
& 0xfc)) {
65 "unsynchronized data 0x%02x at offset %d\n",
72 tsc_process_data(ptsc
);
80 static int tsc_connect(struct serio
*serio
, struct serio_driver
*drv
)
83 struct input_dev
*input_dev
;
86 ptsc
= kzalloc(sizeof(*ptsc
), GFP_KERNEL
);
87 input_dev
= input_allocate_device();
88 if (!ptsc
|| !input_dev
) {
94 ptsc
->dev
= input_dev
;
95 snprintf(ptsc
->phys
, sizeof(ptsc
->phys
), "%s/input0", serio
->phys
);
97 input_dev
->name
= "TSC-10/25/40 Serial TouchScreen";
98 input_dev
->phys
= ptsc
->phys
;
99 input_dev
->id
.bustype
= BUS_RS232
;
100 input_dev
->id
.vendor
= SERIO_TSC40
;
101 input_dev
->id
.product
= 40;
102 input_dev
->id
.version
= 0x0001;
103 input_dev
->dev
.parent
= &serio
->dev
;
105 input_dev
->evbit
[0] = BIT_MASK(EV_KEY
) | BIT_MASK(EV_ABS
);
106 __set_bit(BTN_TOUCH
, input_dev
->keybit
);
107 input_set_abs_params(ptsc
->dev
, ABS_X
, 0, 0x3ff, 0, 0);
108 input_set_abs_params(ptsc
->dev
, ABS_Y
, 0, 0x3ff, 0, 0);
110 serio_set_drvdata(serio
, ptsc
);
112 error
= serio_open(serio
, drv
);
116 error
= input_register_device(ptsc
->dev
);
125 serio_set_drvdata(serio
, NULL
);
127 input_free_device(input_dev
);
132 static void tsc_disconnect(struct serio
*serio
)
134 struct tsc_ser
*ptsc
= serio_get_drvdata(serio
);
138 input_unregister_device(ptsc
->dev
);
141 serio_set_drvdata(serio
, NULL
);
144 static const struct serio_device_id tsc_serio_ids
[] = {
147 .proto
= SERIO_TSC40
,
153 MODULE_DEVICE_TABLE(serio
, tsc_serio_ids
);
155 #define DRIVER_DESC "TSC-10/25/40 serial touchscreen driver"
157 static struct serio_driver tsc_drv
= {
161 .description
= DRIVER_DESC
,
162 .id_table
= tsc_serio_ids
,
163 .interrupt
= tsc_interrupt
,
164 .connect
= tsc_connect
,
165 .disconnect
= tsc_disconnect
,
168 module_serio_driver(tsc_drv
);
170 MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
171 MODULE_DESCRIPTION(DRIVER_DESC
);
172 MODULE_LICENSE("GPL v2");