14feacbc2SBenjamin Tissoires /*
24feacbc2SBenjamin Tissoires  *  Driver for Ntrig/Microsoft Touchscreens over SPI
34feacbc2SBenjamin Tissoires  *
44feacbc2SBenjamin Tissoires  *  Copyright (c) 2016 Red Hat Inc.
54feacbc2SBenjamin Tissoires  */
64feacbc2SBenjamin Tissoires 
74feacbc2SBenjamin Tissoires /*
84feacbc2SBenjamin Tissoires  * This program is free software; you can redistribute it and/or modify it
94feacbc2SBenjamin Tissoires  * under the terms of the GNU General Public License as published by the Free
104feacbc2SBenjamin Tissoires  * Software Foundation; version 2 of the License.
114feacbc2SBenjamin Tissoires  */
124feacbc2SBenjamin Tissoires 
134feacbc2SBenjamin Tissoires #include <linux/kernel.h>
144feacbc2SBenjamin Tissoires 
154feacbc2SBenjamin Tissoires #include <linux/delay.h>
164feacbc2SBenjamin Tissoires #include <linux/gpio/consumer.h>
174feacbc2SBenjamin Tissoires #include <linux/input.h>
184feacbc2SBenjamin Tissoires #include <linux/input/mt.h>
194feacbc2SBenjamin Tissoires #include <linux/interrupt.h>
204feacbc2SBenjamin Tissoires #include <linux/module.h>
214feacbc2SBenjamin Tissoires #include <linux/slab.h>
224feacbc2SBenjamin Tissoires #include <linux/spi/spi.h>
234feacbc2SBenjamin Tissoires #include <linux/acpi.h>
244feacbc2SBenjamin Tissoires 
254feacbc2SBenjamin Tissoires #include <asm/unaligned.h>
264feacbc2SBenjamin Tissoires 
274feacbc2SBenjamin Tissoires #define SURFACE3_PACKET_SIZE	264
284feacbc2SBenjamin Tissoires 
29*427ee206SStephen Just #define SURFACE3_REPORT_TOUCH	0xd2
30*427ee206SStephen Just 
314feacbc2SBenjamin Tissoires struct surface3_ts_data {
324feacbc2SBenjamin Tissoires 	struct spi_device *spi;
334feacbc2SBenjamin Tissoires 	struct gpio_desc *gpiod_rst[2];
344feacbc2SBenjamin Tissoires 	struct input_dev *input_dev;
354feacbc2SBenjamin Tissoires 
364feacbc2SBenjamin Tissoires 	u8 rd_buf[SURFACE3_PACKET_SIZE]		____cacheline_aligned;
374feacbc2SBenjamin Tissoires };
384feacbc2SBenjamin Tissoires 
394feacbc2SBenjamin Tissoires struct surface3_ts_data_finger {
404feacbc2SBenjamin Tissoires 	u8 status;
414feacbc2SBenjamin Tissoires 	__le16 tracking_id;
424feacbc2SBenjamin Tissoires 	__le16 x;
434feacbc2SBenjamin Tissoires 	__le16 cx;
444feacbc2SBenjamin Tissoires 	__le16 y;
454feacbc2SBenjamin Tissoires 	__le16 cy;
464feacbc2SBenjamin Tissoires 	__le16 width;
474feacbc2SBenjamin Tissoires 	__le16 height;
484feacbc2SBenjamin Tissoires 	u32 padding;
494feacbc2SBenjamin Tissoires } __packed;
504feacbc2SBenjamin Tissoires 
514feacbc2SBenjamin Tissoires static int surface3_spi_read(struct surface3_ts_data *ts_data)
524feacbc2SBenjamin Tissoires {
534feacbc2SBenjamin Tissoires 	struct spi_device *spi = ts_data->spi;
544feacbc2SBenjamin Tissoires 
554feacbc2SBenjamin Tissoires 	memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf));
564feacbc2SBenjamin Tissoires 	return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf));
574feacbc2SBenjamin Tissoires }
584feacbc2SBenjamin Tissoires 
594feacbc2SBenjamin Tissoires static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
604feacbc2SBenjamin Tissoires 				   struct surface3_ts_data_finger *finger)
614feacbc2SBenjamin Tissoires {
624feacbc2SBenjamin Tissoires 	int st = finger->status & 0x01;
634feacbc2SBenjamin Tissoires 	int slot;
644feacbc2SBenjamin Tissoires 
654feacbc2SBenjamin Tissoires 	slot = input_mt_get_slot_by_key(ts_data->input_dev,
664feacbc2SBenjamin Tissoires 				get_unaligned_le16(&finger->tracking_id));
674feacbc2SBenjamin Tissoires 	if (slot < 0)
684feacbc2SBenjamin Tissoires 		return;
694feacbc2SBenjamin Tissoires 
704feacbc2SBenjamin Tissoires 	input_mt_slot(ts_data->input_dev, slot);
714feacbc2SBenjamin Tissoires 	input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st);
724feacbc2SBenjamin Tissoires 	if (st) {
734feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
744feacbc2SBenjamin Tissoires 				 ABS_MT_POSITION_X,
754feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->x));
764feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
774feacbc2SBenjamin Tissoires 				 ABS_MT_POSITION_Y,
784feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->y));
794feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
804feacbc2SBenjamin Tissoires 				 ABS_MT_WIDTH_MAJOR,
814feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->width));
824feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
834feacbc2SBenjamin Tissoires 				 ABS_MT_WIDTH_MINOR,
844feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->height));
854feacbc2SBenjamin Tissoires 	}
864feacbc2SBenjamin Tissoires }
874feacbc2SBenjamin Tissoires 
88*427ee206SStephen Just static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
894feacbc2SBenjamin Tissoires {
904feacbc2SBenjamin Tissoires 	u16 timestamp;
914feacbc2SBenjamin Tissoires 	unsigned int i;
924feacbc2SBenjamin Tissoires 	timestamp = get_unaligned_le16(&data[15]);
934feacbc2SBenjamin Tissoires 
944feacbc2SBenjamin Tissoires 	for (i = 0; i < 13; i++) {
954feacbc2SBenjamin Tissoires 		struct surface3_ts_data_finger *finger;
964feacbc2SBenjamin Tissoires 
974feacbc2SBenjamin Tissoires 		finger = (struct surface3_ts_data_finger *)&data[17 +
984feacbc2SBenjamin Tissoires 				i * sizeof(struct surface3_ts_data_finger)];
994feacbc2SBenjamin Tissoires 
1004feacbc2SBenjamin Tissoires 		/*
1014feacbc2SBenjamin Tissoires 		 * When bit 5 of status is 1, it marks the end of the report:
1024feacbc2SBenjamin Tissoires 		 * - touch present: 0xe7
1034feacbc2SBenjamin Tissoires 		 * - touch released: 0xe4
1044feacbc2SBenjamin Tissoires 		 * - nothing valuable: 0xff
1054feacbc2SBenjamin Tissoires 		 */
1064feacbc2SBenjamin Tissoires 		if (finger->status & 0x10)
1074feacbc2SBenjamin Tissoires 			break;
1084feacbc2SBenjamin Tissoires 
1094feacbc2SBenjamin Tissoires 		surface3_spi_report_touch(ts_data, finger);
1104feacbc2SBenjamin Tissoires 	}
1114feacbc2SBenjamin Tissoires 
1124feacbc2SBenjamin Tissoires 	input_mt_sync_frame(ts_data->input_dev);
1134feacbc2SBenjamin Tissoires 	input_sync(ts_data->input_dev);
1144feacbc2SBenjamin Tissoires }
1154feacbc2SBenjamin Tissoires 
116*427ee206SStephen Just static void surface3_spi_process(struct surface3_ts_data *ts_data)
117*427ee206SStephen Just {
118*427ee206SStephen Just 	const char header[] = {
119*427ee206SStephen Just 		0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01
120*427ee206SStephen Just 	};
121*427ee206SStephen Just 	u8 *data = ts_data->rd_buf;
122*427ee206SStephen Just 
123*427ee206SStephen Just 	if (memcmp(header, data, sizeof(header)))
124*427ee206SStephen Just 		dev_err(&ts_data->spi->dev,
125*427ee206SStephen Just 			"%s header error: %*ph, ignoring...\n",
126*427ee206SStephen Just 			__func__, (int)sizeof(header), data);
127*427ee206SStephen Just 
128*427ee206SStephen Just 	if (data[9] == SURFACE3_REPORT_TOUCH)
129*427ee206SStephen Just 		surface3_spi_process_touch(ts_data, data);
130*427ee206SStephen Just 	else
131*427ee206SStephen Just 		dev_err(&ts_data->spi->dev,
132*427ee206SStephen Just 			"%s unknown packet type: %x, ignoring...\n",
133*427ee206SStephen Just 			__func__, data[9]);
134*427ee206SStephen Just }
135*427ee206SStephen Just 
1364feacbc2SBenjamin Tissoires static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
1374feacbc2SBenjamin Tissoires {
1384feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data = dev_id;
1394feacbc2SBenjamin Tissoires 
1404feacbc2SBenjamin Tissoires 	if (surface3_spi_read(data))
1414feacbc2SBenjamin Tissoires 		return IRQ_HANDLED;
1424feacbc2SBenjamin Tissoires 
1434feacbc2SBenjamin Tissoires 	dev_dbg(&data->spi->dev, "%s received -> %*ph\n",
1444feacbc2SBenjamin Tissoires 		__func__, SURFACE3_PACKET_SIZE, data->rd_buf);
1454feacbc2SBenjamin Tissoires 	surface3_spi_process(data);
1464feacbc2SBenjamin Tissoires 
1474feacbc2SBenjamin Tissoires 	return IRQ_HANDLED;
1484feacbc2SBenjamin Tissoires }
1494feacbc2SBenjamin Tissoires 
1504feacbc2SBenjamin Tissoires static void surface3_spi_power(struct surface3_ts_data *data, bool on)
1514feacbc2SBenjamin Tissoires {
1524feacbc2SBenjamin Tissoires 	gpiod_set_value(data->gpiod_rst[0], on);
1534feacbc2SBenjamin Tissoires 	gpiod_set_value(data->gpiod_rst[1], on);
1544feacbc2SBenjamin Tissoires 	/* let the device settle a little */
1554feacbc2SBenjamin Tissoires 	msleep(20);
1564feacbc2SBenjamin Tissoires }
1574feacbc2SBenjamin Tissoires 
1584feacbc2SBenjamin Tissoires /**
1594feacbc2SBenjamin Tissoires  * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
1604feacbc2SBenjamin Tissoires  *
1614feacbc2SBenjamin Tissoires  * @ts: surface3_spi_ts_data pointer
1624feacbc2SBenjamin Tissoires  */
1634feacbc2SBenjamin Tissoires static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
1644feacbc2SBenjamin Tissoires {
1654feacbc2SBenjamin Tissoires 	int error;
1664feacbc2SBenjamin Tissoires 	struct device *dev;
1674feacbc2SBenjamin Tissoires 	struct gpio_desc *gpiod;
1684feacbc2SBenjamin Tissoires 	int i;
1694feacbc2SBenjamin Tissoires 
1704feacbc2SBenjamin Tissoires 	dev = &data->spi->dev;
1714feacbc2SBenjamin Tissoires 
1724feacbc2SBenjamin Tissoires 	/* Get the reset lines GPIO pin number */
1734feacbc2SBenjamin Tissoires 	for (i = 0; i < 2; i++) {
1744feacbc2SBenjamin Tissoires 		gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
1754feacbc2SBenjamin Tissoires 		if (IS_ERR(gpiod)) {
1764feacbc2SBenjamin Tissoires 			error = PTR_ERR(gpiod);
1774feacbc2SBenjamin Tissoires 			if (error != -EPROBE_DEFER)
1784feacbc2SBenjamin Tissoires 				dev_err(dev,
1794feacbc2SBenjamin Tissoires 					"Failed to get power GPIO %d: %d\n",
1804feacbc2SBenjamin Tissoires 					i,
1814feacbc2SBenjamin Tissoires 					error);
1824feacbc2SBenjamin Tissoires 			return error;
1834feacbc2SBenjamin Tissoires 		}
1844feacbc2SBenjamin Tissoires 
1854feacbc2SBenjamin Tissoires 		data->gpiod_rst[i] = gpiod;
1864feacbc2SBenjamin Tissoires 	}
1874feacbc2SBenjamin Tissoires 
1884feacbc2SBenjamin Tissoires 	return 0;
1894feacbc2SBenjamin Tissoires }
1904feacbc2SBenjamin Tissoires 
191*427ee206SStephen Just static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
1924feacbc2SBenjamin Tissoires {
1934feacbc2SBenjamin Tissoires 	struct input_dev *input;
1944feacbc2SBenjamin Tissoires 	int error;
1954feacbc2SBenjamin Tissoires 
1964feacbc2SBenjamin Tissoires 	input = devm_input_allocate_device(&data->spi->dev);
1974feacbc2SBenjamin Tissoires 	if (!input)
1984feacbc2SBenjamin Tissoires 		return -ENOMEM;
1994feacbc2SBenjamin Tissoires 
2004feacbc2SBenjamin Tissoires 	data->input_dev = input;
2014feacbc2SBenjamin Tissoires 
2024feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0);
2034feacbc2SBenjamin Tissoires 	input_abs_set_res(input, ABS_MT_POSITION_X, 40);
2044feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0);
2054feacbc2SBenjamin Tissoires 	input_abs_set_res(input, ABS_MT_POSITION_Y, 48);
2064feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0);
2074feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0);
2084feacbc2SBenjamin Tissoires 	input_mt_init_slots(input, 10, INPUT_MT_DIRECT);
2094feacbc2SBenjamin Tissoires 
2104feacbc2SBenjamin Tissoires 	input->name = "Surface3 SPI Capacitive TouchScreen";
2114feacbc2SBenjamin Tissoires 	input->phys = "input/ts";
2124feacbc2SBenjamin Tissoires 	input->id.bustype = BUS_SPI;
2134feacbc2SBenjamin Tissoires 	input->id.vendor = 0x045e;	/* Microsoft */
214*427ee206SStephen Just 	input->id.product = 0x0001;
2154feacbc2SBenjamin Tissoires 	input->id.version = 0x0000;
2164feacbc2SBenjamin Tissoires 
2174feacbc2SBenjamin Tissoires 	error = input_register_device(input);
2184feacbc2SBenjamin Tissoires 	if (error) {
2194feacbc2SBenjamin Tissoires 		dev_err(&data->spi->dev,
2204feacbc2SBenjamin Tissoires 			"Failed to register input device: %d", error);
2214feacbc2SBenjamin Tissoires 		return error;
2224feacbc2SBenjamin Tissoires 	}
2234feacbc2SBenjamin Tissoires 
2244feacbc2SBenjamin Tissoires 	return 0;
2254feacbc2SBenjamin Tissoires }
2264feacbc2SBenjamin Tissoires 
2274feacbc2SBenjamin Tissoires static int surface3_spi_probe(struct spi_device *spi)
2284feacbc2SBenjamin Tissoires {
2294feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data;
2304feacbc2SBenjamin Tissoires 	int error;
2314feacbc2SBenjamin Tissoires 
2324feacbc2SBenjamin Tissoires 	/* Set up SPI*/
2334feacbc2SBenjamin Tissoires 	spi->bits_per_word = 8;
2344feacbc2SBenjamin Tissoires 	spi->mode = SPI_MODE_0;
2354feacbc2SBenjamin Tissoires 	error = spi_setup(spi);
2364feacbc2SBenjamin Tissoires 	if (error)
2374feacbc2SBenjamin Tissoires 		return error;
2384feacbc2SBenjamin Tissoires 
2394feacbc2SBenjamin Tissoires 	data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
2404feacbc2SBenjamin Tissoires 	if (!data)
2414feacbc2SBenjamin Tissoires 		return -ENOMEM;
2424feacbc2SBenjamin Tissoires 
2434feacbc2SBenjamin Tissoires 	data->spi = spi;
2444feacbc2SBenjamin Tissoires 	spi_set_drvdata(spi, data);
2454feacbc2SBenjamin Tissoires 
2464feacbc2SBenjamin Tissoires 	error = surface3_spi_get_gpio_config(data);
2474feacbc2SBenjamin Tissoires 	if (error)
2484feacbc2SBenjamin Tissoires 		return error;
2494feacbc2SBenjamin Tissoires 
2504feacbc2SBenjamin Tissoires 	surface3_spi_power(data, true);
2514feacbc2SBenjamin Tissoires 	surface3_spi_power(data, false);
2524feacbc2SBenjamin Tissoires 	surface3_spi_power(data, true);
2534feacbc2SBenjamin Tissoires 
254*427ee206SStephen Just 	error = surface3_spi_create_touch_input(data);
2554feacbc2SBenjamin Tissoires 	if (error)
2564feacbc2SBenjamin Tissoires 		return error;
2574feacbc2SBenjamin Tissoires 
2584feacbc2SBenjamin Tissoires 	error = devm_request_threaded_irq(&spi->dev, spi->irq,
2594feacbc2SBenjamin Tissoires 					  NULL, surface3_spi_irq_handler,
2604feacbc2SBenjamin Tissoires 					  IRQF_ONESHOT,
2614feacbc2SBenjamin Tissoires 					  "Surface3-irq", data);
2624feacbc2SBenjamin Tissoires 	if (error)
2634feacbc2SBenjamin Tissoires 		return error;
2644feacbc2SBenjamin Tissoires 
2654feacbc2SBenjamin Tissoires 	return 0;
2664feacbc2SBenjamin Tissoires }
2674feacbc2SBenjamin Tissoires 
2684feacbc2SBenjamin Tissoires static int __maybe_unused surface3_spi_suspend(struct device *dev)
2694feacbc2SBenjamin Tissoires {
2704feacbc2SBenjamin Tissoires 	struct spi_device *spi = to_spi_device(dev);
2714feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data = spi_get_drvdata(spi);
2724feacbc2SBenjamin Tissoires 
2734feacbc2SBenjamin Tissoires 	disable_irq(data->spi->irq);
2744feacbc2SBenjamin Tissoires 
2754feacbc2SBenjamin Tissoires 	surface3_spi_power(data, false);
2764feacbc2SBenjamin Tissoires 
2774feacbc2SBenjamin Tissoires 	return 0;
2784feacbc2SBenjamin Tissoires }
2794feacbc2SBenjamin Tissoires 
2804feacbc2SBenjamin Tissoires static int __maybe_unused surface3_spi_resume(struct device *dev)
2814feacbc2SBenjamin Tissoires {
2824feacbc2SBenjamin Tissoires 	struct spi_device *spi = to_spi_device(dev);
2834feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data = spi_get_drvdata(spi);
2844feacbc2SBenjamin Tissoires 
2854feacbc2SBenjamin Tissoires 	surface3_spi_power(data, true);
2864feacbc2SBenjamin Tissoires 
2874feacbc2SBenjamin Tissoires 	enable_irq(data->spi->irq);
2884feacbc2SBenjamin Tissoires 
2894feacbc2SBenjamin Tissoires 	return 0;
2904feacbc2SBenjamin Tissoires }
2914feacbc2SBenjamin Tissoires 
2924feacbc2SBenjamin Tissoires static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
2934feacbc2SBenjamin Tissoires 			 surface3_spi_suspend,
2944feacbc2SBenjamin Tissoires 			 surface3_spi_resume);
2954feacbc2SBenjamin Tissoires 
2964feacbc2SBenjamin Tissoires #ifdef CONFIG_ACPI
2974feacbc2SBenjamin Tissoires static const struct acpi_device_id surface3_spi_acpi_match[] = {
2984feacbc2SBenjamin Tissoires 	{ "MSHW0037", 0 },
2994feacbc2SBenjamin Tissoires 	{ }
3004feacbc2SBenjamin Tissoires };
3014feacbc2SBenjamin Tissoires MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match);
3024feacbc2SBenjamin Tissoires #endif
3034feacbc2SBenjamin Tissoires 
3044feacbc2SBenjamin Tissoires static struct spi_driver surface3_spi_driver = {
3054feacbc2SBenjamin Tissoires 	.driver = {
3064feacbc2SBenjamin Tissoires 		.name	= "Surface3-spi",
3074feacbc2SBenjamin Tissoires 		.acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
3084feacbc2SBenjamin Tissoires 		.pm = &surface3_spi_pm_ops,
3094feacbc2SBenjamin Tissoires 	},
3104feacbc2SBenjamin Tissoires 	.probe = surface3_spi_probe,
3114feacbc2SBenjamin Tissoires };
3124feacbc2SBenjamin Tissoires 
3134feacbc2SBenjamin Tissoires module_spi_driver(surface3_spi_driver);
3144feacbc2SBenjamin Tissoires 
3154feacbc2SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <[email protected]>");
3164feacbc2SBenjamin Tissoires MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver");
3174feacbc2SBenjamin Tissoires MODULE_LICENSE("GPL v2");
318