linux/drivers/input/touchscreen/tsc40.c
<<
>>
Prefs
   1/*
   2 * TSC-40 serial touchscreen driver. It should be compatible with
   3 * TSC-10 and 25.
   4 *
   5 * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
   6 * License: GPLv2 as published by the FSF.
   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
  16struct 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
  24static 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
  41static 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
  80static 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
 122fail3:
 123        serio_close(serio);
 124fail2:
 125        serio_set_drvdata(serio, NULL);
 126fail1:
 127        input_free_device(input_dev);
 128        kfree(ptsc);
 129        return error;
 130}
 131
 132static 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
 144static 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};
 153MODULE_DEVICE_TABLE(serio, tsc_serio_ids);
 154
 155#define DRIVER_DESC    "TSC-10/25/40 serial touchscreen driver"
 156
 157static 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
 168module_serio_driver(tsc_drv);
 169
 170MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>");
 171MODULE_DESCRIPTION(DRIVER_DESC);
 172MODULE_LICENSE("GPL v2");
 173