root/drivers/input/touchscreen/tsc40.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tsc_process_data
  2. tsc_interrupt
  3. tsc_connect
  4. tsc_disconnect

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * TSC-40 serial touchscreen driver. It should be compatible with
   4  * TSC-10 and 25.
   5  *
   6  * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
   7  */
   8 
   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>
  14 
  15 #define PACKET_LENGTH  5
  16 struct tsc_ser {
  17         struct input_dev *dev;
  18         struct serio *serio;
  19         u32 idx;
  20         unsigned char data[PACKET_LENGTH];
  21         char phys[32];
  22 };
  23 
  24 static void tsc_process_data(struct tsc_ser *ptsc)
  25 {
  26         struct input_dev *dev = ptsc->dev;
  27         u8 *data = ptsc->data;
  28         u32 x;
  29         u32 y;
  30 
  31         x = ((data[1] & 0x03) << 8) | data[2];
  32         y = ((data[3] & 0x03) << 8) | data[4];
  33 
  34         input_report_abs(dev, ABS_X, x);
  35         input_report_abs(dev, ABS_Y, y);
  36         input_report_key(dev, BTN_TOUCH, 1);
  37 
  38         input_sync(dev);
  39 }
  40 
  41 static irqreturn_t tsc_interrupt(struct serio *serio,
  42                 unsigned char data, unsigned int flags)
  43 {
  44         struct tsc_ser *ptsc = serio_get_drvdata(serio);
  45         struct input_dev *dev = ptsc->dev;
  46 
  47         ptsc->data[ptsc->idx] = data;
  48         switch (ptsc->idx++) {
  49         case 0:
  50                 if (unlikely((data & 0x3e) != 0x10)) {
  51                         dev_dbg(&serio->dev,
  52                                 "unsynchronized packet start (0x%02x)\n", data);
  53                         ptsc->idx = 0;
  54                 } else if (!(data & 0x01)) {
  55                         input_report_key(dev, BTN_TOUCH, 0);
  56                         input_sync(dev);
  57                         ptsc->idx = 0;
  58                 }
  59                 break;
  60 
  61         case 1:
  62         case 3:
  63                 if (unlikely(data & 0xfc)) {
  64                         dev_dbg(&serio->dev,
  65                                 "unsynchronized data 0x%02x at offset %d\n",
  66                                 data, ptsc->idx - 1);
  67                         ptsc->idx = 0;
  68                 }
  69                 break;
  70 
  71         case 4:
  72                 tsc_process_data(ptsc);
  73                 ptsc->idx = 0;
  74                 break;
  75         }
  76 
  77         return IRQ_HANDLED;
  78 }
  79 
  80 static int tsc_connect(struct serio *serio, struct serio_driver *drv)
  81 {
  82         struct tsc_ser *ptsc;
  83         struct input_dev *input_dev;
  84         int error;
  85 
  86         ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
  87         input_dev = input_allocate_device();
  88         if (!ptsc || !input_dev) {
  89                 error = -ENOMEM;
  90                 goto fail1;
  91         }
  92 
  93         ptsc->serio = serio;
  94         ptsc->dev = input_dev;
  95         snprintf(ptsc->phys, sizeof(ptsc->phys), "%s/input0", serio->phys);
  96 
  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;
 104 
 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);
 109 
 110         serio_set_drvdata(serio, ptsc);
 111 
 112         error = serio_open(serio, drv);
 113         if (error)
 114                 goto fail2;
 115 
 116         error = input_register_device(ptsc->dev);
 117         if (error)
 118                 goto fail3;
 119 
 120         return 0;
 121 
 122 fail3:
 123         serio_close(serio);
 124 fail2:
 125         serio_set_drvdata(serio, NULL);
 126 fail1:
 127         input_free_device(input_dev);
 128         kfree(ptsc);
 129         return error;
 130 }
 131 
 132 static void tsc_disconnect(struct serio *serio)
 133 {
 134         struct tsc_ser *ptsc = serio_get_drvdata(serio);
 135 
 136         serio_close(serio);
 137 
 138         input_unregister_device(ptsc->dev);
 139         kfree(ptsc);
 140 
 141         serio_set_drvdata(serio, NULL);
 142 }
 143 
 144 static const struct serio_device_id tsc_serio_ids[] = {
 145         {
 146                 .type   = SERIO_RS232,
 147                 .proto  = SERIO_TSC40,
 148                 .id     = SERIO_ANY,
 149                 .extra  = SERIO_ANY,
 150         },
 151         { 0 }
 152 };
 153 MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
 154 
 155 #define DRIVER_DESC    "TSC-10/25/40 serial touchscreen driver"
 156 
 157 static struct serio_driver tsc_drv = {
 158         .driver = {
 159                 .name   = "tsc40",
 160         },
 161         .description    = DRIVER_DESC,
 162         .id_table       = tsc_serio_ids,
 163         .interrupt      = tsc_interrupt,
 164         .connect        = tsc_connect,
 165         .disconnect     = tsc_disconnect,
 166 };
 167 
 168 module_serio_driver(tsc_drv);
 169 
 170 MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
 171 MODULE_DESCRIPTION(DRIVER_DESC);
 172 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */