blob: e18e7425de8e9a8f6d3351cc3603489fd0f54503 [file] [log] [blame]
Benjamin Tissoires4feacbc2016-05-19 09:24:06 -07001/*
2 * Driver for Ntrig/Microsoft Touchscreens over SPI
3 *
4 * Copyright (c) 2016 Red Hat Inc.
5 */
6
7/*
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; version 2 of the License.
11 */
12
13#include <linux/kernel.h>
14
15#include <linux/delay.h>
16#include <linux/gpio/consumer.h>
17#include <linux/input.h>
18#include <linux/input/mt.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/spi/spi.h>
23#include <linux/acpi.h>
24
25#include <asm/unaligned.h>
26
27#define SURFACE3_PACKET_SIZE 264
28
29struct surface3_ts_data {
30 struct spi_device *spi;
31 struct gpio_desc *gpiod_rst[2];
32 struct input_dev *input_dev;
33
34 u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned;
35};
36
37struct surface3_ts_data_finger {
38 u8 status;
39 __le16 tracking_id;
40 __le16 x;
41 __le16 cx;
42 __le16 y;
43 __le16 cy;
44 __le16 width;
45 __le16 height;
46 u32 padding;
47} __packed;
48
49static int surface3_spi_read(struct surface3_ts_data *ts_data)
50{
51 struct spi_device *spi = ts_data->spi;
52
53 memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf));
54 return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf));
55}
56
57static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
58 struct surface3_ts_data_finger *finger)
59{
60 int st = finger->status & 0x01;
61 int slot;
62
63 slot = input_mt_get_slot_by_key(ts_data->input_dev,
64 get_unaligned_le16(&finger->tracking_id));
65 if (slot < 0)
66 return;
67
68 input_mt_slot(ts_data->input_dev, slot);
69 input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st);
70 if (st) {
71 input_report_abs(ts_data->input_dev,
72 ABS_MT_POSITION_X,
73 get_unaligned_le16(&finger->x));
74 input_report_abs(ts_data->input_dev,
75 ABS_MT_POSITION_Y,
76 get_unaligned_le16(&finger->y));
77 input_report_abs(ts_data->input_dev,
78 ABS_MT_WIDTH_MAJOR,
79 get_unaligned_le16(&finger->width));
80 input_report_abs(ts_data->input_dev,
81 ABS_MT_WIDTH_MINOR,
82 get_unaligned_le16(&finger->height));
83 }
84}
85
86static void surface3_spi_process(struct surface3_ts_data *ts_data)
87{
88 const char header[] = {0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e,
89 0x01, 0xd2, 0x00, 0x80, 0x01, 0x03, 0x03};
90 u8 *data = ts_data->rd_buf;
91 u16 timestamp;
92 unsigned int i;
93
94 if (memcmp(header, data, sizeof(header)))
95 dev_err(&ts_data->spi->dev,
96 "%s header error: %*ph, ignoring...\n",
97 __func__, (int)sizeof(header), data);
98
99 timestamp = get_unaligned_le16(&data[15]);
100
101 for (i = 0; i < 13; i++) {
102 struct surface3_ts_data_finger *finger;
103
104 finger = (struct surface3_ts_data_finger *)&data[17 +
105 i * sizeof(struct surface3_ts_data_finger)];
106
107 /*
108 * When bit 5 of status is 1, it marks the end of the report:
109 * - touch present: 0xe7
110 * - touch released: 0xe4
111 * - nothing valuable: 0xff
112 */
113 if (finger->status & 0x10)
114 break;
115
116 surface3_spi_report_touch(ts_data, finger);
117 }
118
119 input_mt_sync_frame(ts_data->input_dev);
120 input_sync(ts_data->input_dev);
121}
122
123static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
124{
125 struct surface3_ts_data *data = dev_id;
126
127 if (surface3_spi_read(data))
128 return IRQ_HANDLED;
129
130 dev_dbg(&data->spi->dev, "%s received -> %*ph\n",
131 __func__, SURFACE3_PACKET_SIZE, data->rd_buf);
132 surface3_spi_process(data);
133
134 return IRQ_HANDLED;
135}
136
137static void surface3_spi_power(struct surface3_ts_data *data, bool on)
138{
139 gpiod_set_value(data->gpiod_rst[0], on);
140 gpiod_set_value(data->gpiod_rst[1], on);
141 /* let the device settle a little */
142 msleep(20);
143}
144
145/**
146 * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
147 *
148 * @ts: surface3_spi_ts_data pointer
149 */
150static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
151{
152 int error;
153 struct device *dev;
154 struct gpio_desc *gpiod;
155 int i;
156
157 dev = &data->spi->dev;
158
159 /* Get the reset lines GPIO pin number */
160 for (i = 0; i < 2; i++) {
161 gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
162 if (IS_ERR(gpiod)) {
163 error = PTR_ERR(gpiod);
164 if (error != -EPROBE_DEFER)
165 dev_err(dev,
166 "Failed to get power GPIO %d: %d\n",
167 i,
168 error);
169 return error;
170 }
171
172 data->gpiod_rst[i] = gpiod;
173 }
174
175 return 0;
176}
177
178static int surface3_spi_create_input(struct surface3_ts_data *data)
179{
180 struct input_dev *input;
181 int error;
182
183 input = devm_input_allocate_device(&data->spi->dev);
184 if (!input)
185 return -ENOMEM;
186
187 data->input_dev = input;
188
189 input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0);
190 input_abs_set_res(input, ABS_MT_POSITION_X, 40);
191 input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0);
192 input_abs_set_res(input, ABS_MT_POSITION_Y, 48);
193 input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0);
194 input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0);
195 input_mt_init_slots(input, 10, INPUT_MT_DIRECT);
196
197 input->name = "Surface3 SPI Capacitive TouchScreen";
198 input->phys = "input/ts";
199 input->id.bustype = BUS_SPI;
200 input->id.vendor = 0x045e; /* Microsoft */
201 input->id.product = 0x0000;
202 input->id.version = 0x0000;
203
204 error = input_register_device(input);
205 if (error) {
206 dev_err(&data->spi->dev,
207 "Failed to register input device: %d", error);
208 return error;
209 }
210
211 return 0;
212}
213
214static int surface3_spi_probe(struct spi_device *spi)
215{
216 struct surface3_ts_data *data;
217 int error;
218
219 /* Set up SPI*/
220 spi->bits_per_word = 8;
221 spi->mode = SPI_MODE_0;
222 error = spi_setup(spi);
223 if (error)
224 return error;
225
226 data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
227 if (!data)
228 return -ENOMEM;
229
230 data->spi = spi;
231 spi_set_drvdata(spi, data);
232
233 error = surface3_spi_get_gpio_config(data);
234 if (error)
235 return error;
236
237 surface3_spi_power(data, true);
238 surface3_spi_power(data, false);
239 surface3_spi_power(data, true);
240
241 error = surface3_spi_create_input(data);
242 if (error)
243 return error;
244
245 error = devm_request_threaded_irq(&spi->dev, spi->irq,
246 NULL, surface3_spi_irq_handler,
247 IRQF_ONESHOT,
248 "Surface3-irq", data);
249 if (error)
250 return error;
251
252 return 0;
253}
254
255static int __maybe_unused surface3_spi_suspend(struct device *dev)
256{
257 struct spi_device *spi = to_spi_device(dev);
258 struct surface3_ts_data *data = spi_get_drvdata(spi);
259
260 disable_irq(data->spi->irq);
261
262 surface3_spi_power(data, false);
263
264 return 0;
265}
266
267static int __maybe_unused surface3_spi_resume(struct device *dev)
268{
269 struct spi_device *spi = to_spi_device(dev);
270 struct surface3_ts_data *data = spi_get_drvdata(spi);
271
272 surface3_spi_power(data, true);
273
274 enable_irq(data->spi->irq);
275
276 return 0;
277}
278
279static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
280 surface3_spi_suspend,
281 surface3_spi_resume);
282
283#ifdef CONFIG_ACPI
284static const struct acpi_device_id surface3_spi_acpi_match[] = {
285 { "MSHW0037", 0 },
286 { }
287};
288MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match);
289#endif
290
291static struct spi_driver surface3_spi_driver = {
292 .driver = {
293 .name = "Surface3-spi",
294 .acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
295 .pm = &surface3_spi_pm_ops,
296 },
297 .probe = surface3_spi_probe,
298};
299
300module_spi_driver(surface3_spi_driver);
301
302MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
303MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver");
304MODULE_LICENSE("GPL v2");