1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24003dff4SRick Koch /*
34003dff4SRick Koch * Touchright serial touchscreen driver
44003dff4SRick Koch *
54003dff4SRick Koch * Copyright (c) 2006 Rick Koch <[email protected]>
64003dff4SRick Koch *
74003dff4SRick Koch * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
84003dff4SRick Koch * Copyright (c) 2004 Vojtech Pavlik
94003dff4SRick Koch * and Dan Streetman <[email protected]>
104003dff4SRick Koch */
114003dff4SRick Koch
124003dff4SRick Koch
134003dff4SRick Koch #include <linux/errno.h>
144003dff4SRick Koch #include <linux/kernel.h>
154003dff4SRick Koch #include <linux/module.h>
164003dff4SRick Koch #include <linux/slab.h>
174003dff4SRick Koch #include <linux/input.h>
184003dff4SRick Koch #include <linux/serio.h>
194003dff4SRick Koch
204003dff4SRick Koch #define DRIVER_DESC "Touchright serial touchscreen driver"
214003dff4SRick Koch
224003dff4SRick Koch MODULE_AUTHOR("Rick Koch <[email protected]>");
234003dff4SRick Koch MODULE_DESCRIPTION(DRIVER_DESC);
244003dff4SRick Koch MODULE_LICENSE("GPL");
254003dff4SRick Koch
264003dff4SRick Koch /*
274003dff4SRick Koch * Definitions & global arrays.
284003dff4SRick Koch */
294003dff4SRick Koch
304003dff4SRick Koch #define TR_FORMAT_TOUCH_BIT 0x01
314003dff4SRick Koch #define TR_FORMAT_STATUS_BYTE 0x40
324003dff4SRick Koch #define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT
334003dff4SRick Koch
344003dff4SRick Koch #define TR_LENGTH 5
354003dff4SRick Koch
364003dff4SRick Koch #define TR_MIN_XC 0
374003dff4SRick Koch #define TR_MAX_XC 0x1ff
384003dff4SRick Koch #define TR_MIN_YC 0
394003dff4SRick Koch #define TR_MAX_YC 0x1ff
404003dff4SRick Koch
414003dff4SRick Koch /*
424003dff4SRick Koch * Per-touchscreen data.
434003dff4SRick Koch */
444003dff4SRick Koch
454003dff4SRick Koch struct tr {
464003dff4SRick Koch struct input_dev *dev;
474003dff4SRick Koch struct serio *serio;
484003dff4SRick Koch int idx;
494003dff4SRick Koch unsigned char data[TR_LENGTH];
504003dff4SRick Koch char phys[32];
514003dff4SRick Koch };
524003dff4SRick Koch
tr_interrupt(struct serio * serio,unsigned char data,unsigned int flags)534003dff4SRick Koch static irqreturn_t tr_interrupt(struct serio *serio,
547d12e780SDavid Howells unsigned char data, unsigned int flags)
554003dff4SRick Koch {
564003dff4SRick Koch struct tr *tr = serio_get_drvdata(serio);
574003dff4SRick Koch struct input_dev *dev = tr->dev;
584003dff4SRick Koch
594003dff4SRick Koch tr->data[tr->idx] = data;
604003dff4SRick Koch
614003dff4SRick Koch if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) {
624003dff4SRick Koch if (++tr->idx == TR_LENGTH) {
634003dff4SRick Koch input_report_abs(dev, ABS_X,
644003dff4SRick Koch (tr->data[1] << 5) | (tr->data[2] >> 1));
654003dff4SRick Koch input_report_abs(dev, ABS_Y,
664003dff4SRick Koch (tr->data[3] << 5) | (tr->data[4] >> 1));
674003dff4SRick Koch input_report_key(dev, BTN_TOUCH,
684003dff4SRick Koch tr->data[0] & TR_FORMAT_TOUCH_BIT);
694003dff4SRick Koch input_sync(dev);
704003dff4SRick Koch tr->idx = 0;
714003dff4SRick Koch }
724003dff4SRick Koch }
734003dff4SRick Koch
744003dff4SRick Koch return IRQ_HANDLED;
754003dff4SRick Koch }
764003dff4SRick Koch
774003dff4SRick Koch /*
784003dff4SRick Koch * tr_disconnect() is the opposite of tr_connect()
794003dff4SRick Koch */
804003dff4SRick Koch
tr_disconnect(struct serio * serio)814003dff4SRick Koch static void tr_disconnect(struct serio *serio)
824003dff4SRick Koch {
834003dff4SRick Koch struct tr *tr = serio_get_drvdata(serio);
844003dff4SRick Koch
854003dff4SRick Koch input_get_device(tr->dev);
864003dff4SRick Koch input_unregister_device(tr->dev);
874003dff4SRick Koch serio_close(serio);
884003dff4SRick Koch serio_set_drvdata(serio, NULL);
894003dff4SRick Koch input_put_device(tr->dev);
904003dff4SRick Koch kfree(tr);
914003dff4SRick Koch }
924003dff4SRick Koch
934003dff4SRick Koch /*
944003dff4SRick Koch * tr_connect() is the routine that is called when someone adds a
954003dff4SRick Koch * new serio device that supports the Touchright protocol and registers it as
964003dff4SRick Koch * an input device.
974003dff4SRick Koch */
984003dff4SRick Koch
tr_connect(struct serio * serio,struct serio_driver * drv)994003dff4SRick Koch static int tr_connect(struct serio *serio, struct serio_driver *drv)
1004003dff4SRick Koch {
1014003dff4SRick Koch struct tr *tr;
1024003dff4SRick Koch struct input_dev *input_dev;
1034003dff4SRick Koch int err;
1044003dff4SRick Koch
105*f81d03d4SErick Archer tr = kzalloc(sizeof(*tr), GFP_KERNEL);
1064003dff4SRick Koch input_dev = input_allocate_device();
1074003dff4SRick Koch if (!tr || !input_dev) {
1084003dff4SRick Koch err = -ENOMEM;
1094003dff4SRick Koch goto fail1;
1104003dff4SRick Koch }
1114003dff4SRick Koch
1124003dff4SRick Koch tr->serio = serio;
1134003dff4SRick Koch tr->dev = input_dev;
1144003dff4SRick Koch snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
1154003dff4SRick Koch
1164003dff4SRick Koch input_dev->name = "Touchright Serial TouchScreen";
1174003dff4SRick Koch input_dev->phys = tr->phys;
1184003dff4SRick Koch input_dev->id.bustype = BUS_RS232;
1194003dff4SRick Koch input_dev->id.vendor = SERIO_TOUCHRIGHT;
1204003dff4SRick Koch input_dev->id.product = 0;
1214003dff4SRick Koch input_dev->id.version = 0x0100;
122a5394fb0SDmitry Torokhov input_dev->dev.parent = &serio->dev;
1237b19ada2SJiri Slaby input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
1247b19ada2SJiri Slaby input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
1254003dff4SRick Koch input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
1264003dff4SRick Koch input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0);
1274003dff4SRick Koch
1284003dff4SRick Koch serio_set_drvdata(serio, tr);
1294003dff4SRick Koch
1304003dff4SRick Koch err = serio_open(serio, drv);
1314003dff4SRick Koch if (err)
1324003dff4SRick Koch goto fail2;
1334003dff4SRick Koch
1344003dff4SRick Koch err = input_register_device(tr->dev);
1354003dff4SRick Koch if (err)
1364003dff4SRick Koch goto fail3;
1374003dff4SRick Koch
1384003dff4SRick Koch return 0;
1394003dff4SRick Koch
1404003dff4SRick Koch fail3: serio_close(serio);
1414003dff4SRick Koch fail2: serio_set_drvdata(serio, NULL);
1424003dff4SRick Koch fail1: input_free_device(input_dev);
1434003dff4SRick Koch kfree(tr);
1444003dff4SRick Koch return err;
1454003dff4SRick Koch }
1464003dff4SRick Koch
1474003dff4SRick Koch /*
1484003dff4SRick Koch * The serio driver structure.
1494003dff4SRick Koch */
1504003dff4SRick Koch
151ef2bc04eSArvind Yadav static const struct serio_device_id tr_serio_ids[] = {
1524003dff4SRick Koch {
1534003dff4SRick Koch .type = SERIO_RS232,
1544003dff4SRick Koch .proto = SERIO_TOUCHRIGHT,
1554003dff4SRick Koch .id = SERIO_ANY,
1564003dff4SRick Koch .extra = SERIO_ANY,
1574003dff4SRick Koch },
1584003dff4SRick Koch { 0 }
1594003dff4SRick Koch };
1604003dff4SRick Koch
1614003dff4SRick Koch MODULE_DEVICE_TABLE(serio, tr_serio_ids);
1624003dff4SRick Koch
1634003dff4SRick Koch static struct serio_driver tr_drv = {
1644003dff4SRick Koch .driver = {
1654003dff4SRick Koch .name = "touchright",
1664003dff4SRick Koch },
1674003dff4SRick Koch .description = DRIVER_DESC,
1684003dff4SRick Koch .id_table = tr_serio_ids,
1694003dff4SRick Koch .interrupt = tr_interrupt,
1704003dff4SRick Koch .connect = tr_connect,
1714003dff4SRick Koch .disconnect = tr_disconnect,
1724003dff4SRick Koch };
1734003dff4SRick Koch
17465ac9f7aSAxel Lin module_serio_driver(tr_drv);
175