Merge tag 'parse-val' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap...
[firefly-linux-kernel-4.4.55.git] / drivers / input / touchscreen / tsc40.c
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
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 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");