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