Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TSC-40 serial touchscreen driver. It should be compatible with
0004  * TSC-10 and 25.
0005  *
0006  * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
0007  */
0008 
0009 #include <linux/kernel.h>
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/input.h>
0013 #include <linux/serio.h>
0014 
0015 #define PACKET_LENGTH  5
0016 struct tsc_ser {
0017     struct input_dev *dev;
0018     struct serio *serio;
0019     u32 idx;
0020     unsigned char data[PACKET_LENGTH];
0021     char phys[32];
0022 };
0023 
0024 static void tsc_process_data(struct tsc_ser *ptsc)
0025 {
0026     struct input_dev *dev = ptsc->dev;
0027     u8 *data = ptsc->data;
0028     u32 x;
0029     u32 y;
0030 
0031     x = ((data[1] & 0x03) << 8) | data[2];
0032     y = ((data[3] & 0x03) << 8) | data[4];
0033 
0034     input_report_abs(dev, ABS_X, x);
0035     input_report_abs(dev, ABS_Y, y);
0036     input_report_key(dev, BTN_TOUCH, 1);
0037 
0038     input_sync(dev);
0039 }
0040 
0041 static irqreturn_t tsc_interrupt(struct serio *serio,
0042         unsigned char data, unsigned int flags)
0043 {
0044     struct tsc_ser *ptsc = serio_get_drvdata(serio);
0045     struct input_dev *dev = ptsc->dev;
0046 
0047     ptsc->data[ptsc->idx] = data;
0048     switch (ptsc->idx++) {
0049     case 0:
0050         if (unlikely((data & 0x3e) != 0x10)) {
0051             dev_dbg(&serio->dev,
0052                 "unsynchronized packet start (0x%02x)\n", data);
0053             ptsc->idx = 0;
0054         } else if (!(data & 0x01)) {
0055             input_report_key(dev, BTN_TOUCH, 0);
0056             input_sync(dev);
0057             ptsc->idx = 0;
0058         }
0059         break;
0060 
0061     case 1:
0062     case 3:
0063         if (unlikely(data & 0xfc)) {
0064             dev_dbg(&serio->dev,
0065                 "unsynchronized data 0x%02x at offset %d\n",
0066                 data, ptsc->idx - 1);
0067             ptsc->idx = 0;
0068         }
0069         break;
0070 
0071     case 4:
0072         tsc_process_data(ptsc);
0073         ptsc->idx = 0;
0074         break;
0075     }
0076 
0077     return IRQ_HANDLED;
0078 }
0079 
0080 static int tsc_connect(struct serio *serio, struct serio_driver *drv)
0081 {
0082     struct tsc_ser *ptsc;
0083     struct input_dev *input_dev;
0084     int error;
0085 
0086     ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
0087     input_dev = input_allocate_device();
0088     if (!ptsc || !input_dev) {
0089         error = -ENOMEM;
0090         goto fail1;
0091     }
0092 
0093     ptsc->serio = serio;
0094     ptsc->dev = input_dev;
0095     snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
0096 
0097     input_dev->name = "TSC-10/25/40 Serial TouchScreen";
0098     input_dev->phys = ptsc->phys;
0099     input_dev->id.bustype = BUS_RS232;
0100     input_dev->id.vendor = SERIO_TSC40;
0101     input_dev->id.product = 40;
0102     input_dev->id.version = 0x0001;
0103     input_dev->dev.parent = &serio->dev;
0104 
0105     input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
0106     __set_bit(BTN_TOUCH, input_dev->keybit);
0107     input_set_abs_params(ptsc->dev, ABS_X, 0, 0x3ff, 0, 0);
0108     input_set_abs_params(ptsc->dev, ABS_Y, 0, 0x3ff, 0, 0);
0109 
0110     serio_set_drvdata(serio, ptsc);
0111 
0112     error = serio_open(serio, drv);
0113     if (error)
0114         goto fail2;
0115 
0116     error = input_register_device(ptsc->dev);
0117     if (error)
0118         goto fail3;
0119 
0120     return 0;
0121 
0122 fail3:
0123     serio_close(serio);
0124 fail2:
0125     serio_set_drvdata(serio, NULL);
0126 fail1:
0127     input_free_device(input_dev);
0128     kfree(ptsc);
0129     return error;
0130 }
0131 
0132 static void tsc_disconnect(struct serio *serio)
0133 {
0134     struct tsc_ser *ptsc = serio_get_drvdata(serio);
0135 
0136     serio_close(serio);
0137 
0138     input_unregister_device(ptsc->dev);
0139     kfree(ptsc);
0140 
0141     serio_set_drvdata(serio, NULL);
0142 }
0143 
0144 static const struct serio_device_id tsc_serio_ids[] = {
0145     {
0146         .type   = SERIO_RS232,
0147         .proto  = SERIO_TSC40,
0148         .id     = SERIO_ANY,
0149         .extra  = SERIO_ANY,
0150     },
0151     { 0 }
0152 };
0153 MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
0154 
0155 #define DRIVER_DESC    "TSC-10/25/40 serial touchscreen driver"
0156 
0157 static struct serio_driver tsc_drv = {
0158     .driver = {
0159         .name   = "tsc40",
0160     },
0161     .description    = DRIVER_DESC,
0162     .id_table   = tsc_serio_ids,
0163     .interrupt      = tsc_interrupt,
0164     .connect    = tsc_connect,
0165     .disconnect     = tsc_disconnect,
0166 };
0167 
0168 module_serio_driver(tsc_drv);
0169 
0170 MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
0171 MODULE_DESCRIPTION(DRIVER_DESC);
0172 MODULE_LICENSE("GPL v2");