xref: /openbmc/linux/drivers/input/touchscreen/surface3_spi.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
24feacbc2SBenjamin Tissoires /*
34feacbc2SBenjamin Tissoires  *  Driver for Ntrig/Microsoft Touchscreens over SPI
44feacbc2SBenjamin Tissoires  *
54feacbc2SBenjamin Tissoires  *  Copyright (c) 2016 Red Hat Inc.
64feacbc2SBenjamin Tissoires  */
74feacbc2SBenjamin Tissoires 
84feacbc2SBenjamin Tissoires 
94feacbc2SBenjamin Tissoires #include <linux/kernel.h>
104feacbc2SBenjamin Tissoires 
114feacbc2SBenjamin Tissoires #include <linux/delay.h>
124feacbc2SBenjamin Tissoires #include <linux/gpio/consumer.h>
134feacbc2SBenjamin Tissoires #include <linux/input.h>
144feacbc2SBenjamin Tissoires #include <linux/input/mt.h>
154feacbc2SBenjamin Tissoires #include <linux/interrupt.h>
164feacbc2SBenjamin Tissoires #include <linux/module.h>
174feacbc2SBenjamin Tissoires #include <linux/slab.h>
184feacbc2SBenjamin Tissoires #include <linux/spi/spi.h>
194feacbc2SBenjamin Tissoires #include <linux/acpi.h>
204feacbc2SBenjamin Tissoires 
214feacbc2SBenjamin Tissoires #include <asm/unaligned.h>
224feacbc2SBenjamin Tissoires 
234feacbc2SBenjamin Tissoires #define SURFACE3_PACKET_SIZE	264
244feacbc2SBenjamin Tissoires 
25427ee206SStephen Just #define SURFACE3_REPORT_TOUCH	0xd2
2672fb4765SStephen Just #define SURFACE3_REPORT_PEN	0x16
27427ee206SStephen Just 
284feacbc2SBenjamin Tissoires struct surface3_ts_data {
294feacbc2SBenjamin Tissoires 	struct spi_device *spi;
304feacbc2SBenjamin Tissoires 	struct gpio_desc *gpiod_rst[2];
314feacbc2SBenjamin Tissoires 	struct input_dev *input_dev;
3272fb4765SStephen Just 	struct input_dev *pen_input_dev;
3372fb4765SStephen Just 	int pen_tool;
344feacbc2SBenjamin Tissoires 
354feacbc2SBenjamin Tissoires 	u8 rd_buf[SURFACE3_PACKET_SIZE]		____cacheline_aligned;
364feacbc2SBenjamin Tissoires };
374feacbc2SBenjamin Tissoires 
384feacbc2SBenjamin Tissoires struct surface3_ts_data_finger {
394feacbc2SBenjamin Tissoires 	u8 status;
404feacbc2SBenjamin Tissoires 	__le16 tracking_id;
414feacbc2SBenjamin Tissoires 	__le16 x;
424feacbc2SBenjamin Tissoires 	__le16 cx;
434feacbc2SBenjamin Tissoires 	__le16 y;
444feacbc2SBenjamin Tissoires 	__le16 cy;
454feacbc2SBenjamin Tissoires 	__le16 width;
464feacbc2SBenjamin Tissoires 	__le16 height;
474feacbc2SBenjamin Tissoires 	u32 padding;
484feacbc2SBenjamin Tissoires } __packed;
494feacbc2SBenjamin Tissoires 
5072fb4765SStephen Just struct surface3_ts_data_pen {
5172fb4765SStephen Just 	u8 status;
5272fb4765SStephen Just 	__le16 x;
5372fb4765SStephen Just 	__le16 y;
5472fb4765SStephen Just 	__le16 pressure;
5572fb4765SStephen Just 	u8 padding;
5672fb4765SStephen Just } __packed;
5772fb4765SStephen Just 
surface3_spi_read(struct surface3_ts_data * ts_data)584feacbc2SBenjamin Tissoires static int surface3_spi_read(struct surface3_ts_data *ts_data)
594feacbc2SBenjamin Tissoires {
604feacbc2SBenjamin Tissoires 	struct spi_device *spi = ts_data->spi;
614feacbc2SBenjamin Tissoires 
624feacbc2SBenjamin Tissoires 	memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf));
634feacbc2SBenjamin Tissoires 	return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf));
644feacbc2SBenjamin Tissoires }
654feacbc2SBenjamin Tissoires 
surface3_spi_report_touch(struct surface3_ts_data * ts_data,struct surface3_ts_data_finger * finger)664feacbc2SBenjamin Tissoires static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
674feacbc2SBenjamin Tissoires 				   struct surface3_ts_data_finger *finger)
684feacbc2SBenjamin Tissoires {
694feacbc2SBenjamin Tissoires 	int st = finger->status & 0x01;
704feacbc2SBenjamin Tissoires 	int slot;
714feacbc2SBenjamin Tissoires 
724feacbc2SBenjamin Tissoires 	slot = input_mt_get_slot_by_key(ts_data->input_dev,
734feacbc2SBenjamin Tissoires 				get_unaligned_le16(&finger->tracking_id));
744feacbc2SBenjamin Tissoires 	if (slot < 0)
754feacbc2SBenjamin Tissoires 		return;
764feacbc2SBenjamin Tissoires 
774feacbc2SBenjamin Tissoires 	input_mt_slot(ts_data->input_dev, slot);
784feacbc2SBenjamin Tissoires 	input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st);
794feacbc2SBenjamin Tissoires 	if (st) {
804feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
814feacbc2SBenjamin Tissoires 				 ABS_MT_POSITION_X,
824feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->x));
834feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
844feacbc2SBenjamin Tissoires 				 ABS_MT_POSITION_Y,
854feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->y));
864feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
874feacbc2SBenjamin Tissoires 				 ABS_MT_WIDTH_MAJOR,
884feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->width));
894feacbc2SBenjamin Tissoires 		input_report_abs(ts_data->input_dev,
904feacbc2SBenjamin Tissoires 				 ABS_MT_WIDTH_MINOR,
914feacbc2SBenjamin Tissoires 				 get_unaligned_le16(&finger->height));
924feacbc2SBenjamin Tissoires 	}
934feacbc2SBenjamin Tissoires }
944feacbc2SBenjamin Tissoires 
surface3_spi_process_touch(struct surface3_ts_data * ts_data,u8 * data)95427ee206SStephen Just static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
964feacbc2SBenjamin Tissoires {
974feacbc2SBenjamin Tissoires 	unsigned int i;
984feacbc2SBenjamin Tissoires 
994feacbc2SBenjamin Tissoires 	for (i = 0; i < 13; i++) {
1004feacbc2SBenjamin Tissoires 		struct surface3_ts_data_finger *finger;
1014feacbc2SBenjamin Tissoires 
1024feacbc2SBenjamin Tissoires 		finger = (struct surface3_ts_data_finger *)&data[17 +
1034feacbc2SBenjamin Tissoires 				i * sizeof(struct surface3_ts_data_finger)];
1044feacbc2SBenjamin Tissoires 
1054feacbc2SBenjamin Tissoires 		/*
1064feacbc2SBenjamin Tissoires 		 * When bit 5 of status is 1, it marks the end of the report:
1074feacbc2SBenjamin Tissoires 		 * - touch present: 0xe7
1084feacbc2SBenjamin Tissoires 		 * - touch released: 0xe4
1094feacbc2SBenjamin Tissoires 		 * - nothing valuable: 0xff
1104feacbc2SBenjamin Tissoires 		 */
1114feacbc2SBenjamin Tissoires 		if (finger->status & 0x10)
1124feacbc2SBenjamin Tissoires 			break;
1134feacbc2SBenjamin Tissoires 
1144feacbc2SBenjamin Tissoires 		surface3_spi_report_touch(ts_data, finger);
1154feacbc2SBenjamin Tissoires 	}
1164feacbc2SBenjamin Tissoires 
1174feacbc2SBenjamin Tissoires 	input_mt_sync_frame(ts_data->input_dev);
1184feacbc2SBenjamin Tissoires 	input_sync(ts_data->input_dev);
1194feacbc2SBenjamin Tissoires }
1204feacbc2SBenjamin Tissoires 
surface3_spi_report_pen(struct surface3_ts_data * ts_data,struct surface3_ts_data_pen * pen)12172fb4765SStephen Just static void surface3_spi_report_pen(struct surface3_ts_data *ts_data,
12272fb4765SStephen Just 				    struct surface3_ts_data_pen *pen)
12372fb4765SStephen Just {
12472fb4765SStephen Just 	struct input_dev *dev = ts_data->pen_input_dev;
12572fb4765SStephen Just 	int st = pen->status;
12672fb4765SStephen Just 	int prox = st & 0x01;
12772fb4765SStephen Just 	int rubber = st & 0x18;
12872fb4765SStephen Just 	int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
12972fb4765SStephen Just 
13072fb4765SStephen Just 	/* fake proximity out to switch tools */
13172fb4765SStephen Just 	if (ts_data->pen_tool != tool) {
13272fb4765SStephen Just 		input_report_key(dev, ts_data->pen_tool, 0);
13372fb4765SStephen Just 		input_sync(dev);
13472fb4765SStephen Just 		ts_data->pen_tool = tool;
13572fb4765SStephen Just 	}
13672fb4765SStephen Just 
13772fb4765SStephen Just 	input_report_key(dev, BTN_TOUCH, st & 0x12);
13872fb4765SStephen Just 
13972fb4765SStephen Just 	input_report_key(dev, ts_data->pen_tool, prox);
14072fb4765SStephen Just 
14172fb4765SStephen Just 	if (st) {
14272fb4765SStephen Just 		input_report_key(dev,
14372fb4765SStephen Just 				 BTN_STYLUS,
14472fb4765SStephen Just 				 st & 0x04);
14572fb4765SStephen Just 
14672fb4765SStephen Just 		input_report_abs(dev,
14772fb4765SStephen Just 				 ABS_X,
14872fb4765SStephen Just 				 get_unaligned_le16(&pen->x));
14972fb4765SStephen Just 		input_report_abs(dev,
15072fb4765SStephen Just 				 ABS_Y,
15172fb4765SStephen Just 				 get_unaligned_le16(&pen->y));
15272fb4765SStephen Just 		input_report_abs(dev,
15372fb4765SStephen Just 				 ABS_PRESSURE,
15472fb4765SStephen Just 				 get_unaligned_le16(&pen->pressure));
15572fb4765SStephen Just 	}
15672fb4765SStephen Just }
15772fb4765SStephen Just 
surface3_spi_process_pen(struct surface3_ts_data * ts_data,u8 * data)15872fb4765SStephen Just static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data)
15972fb4765SStephen Just {
16072fb4765SStephen Just 	struct surface3_ts_data_pen *pen;
16172fb4765SStephen Just 
16272fb4765SStephen Just 	pen = (struct surface3_ts_data_pen *)&data[15];
16372fb4765SStephen Just 
16472fb4765SStephen Just 	surface3_spi_report_pen(ts_data, pen);
16572fb4765SStephen Just 	input_sync(ts_data->pen_input_dev);
16672fb4765SStephen Just }
16772fb4765SStephen Just 
surface3_spi_process(struct surface3_ts_data * ts_data)168427ee206SStephen Just static void surface3_spi_process(struct surface3_ts_data *ts_data)
169427ee206SStephen Just {
170023c437aSColin Ian King 	static const char header[] = {
171427ee206SStephen Just 		0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01
172427ee206SStephen Just 	};
173427ee206SStephen Just 	u8 *data = ts_data->rd_buf;
174427ee206SStephen Just 
175427ee206SStephen Just 	if (memcmp(header, data, sizeof(header)))
176427ee206SStephen Just 		dev_err(&ts_data->spi->dev,
177427ee206SStephen Just 			"%s header error: %*ph, ignoring...\n",
178427ee206SStephen Just 			__func__, (int)sizeof(header), data);
179427ee206SStephen Just 
18072fb4765SStephen Just 	switch (data[9]) {
18172fb4765SStephen Just 	case SURFACE3_REPORT_TOUCH:
182427ee206SStephen Just 		surface3_spi_process_touch(ts_data, data);
18372fb4765SStephen Just 		break;
18472fb4765SStephen Just 	case SURFACE3_REPORT_PEN:
18572fb4765SStephen Just 		surface3_spi_process_pen(ts_data, data);
18672fb4765SStephen Just 		break;
18772fb4765SStephen Just 	default:
188427ee206SStephen Just 		dev_err(&ts_data->spi->dev,
189427ee206SStephen Just 			"%s unknown packet type: %x, ignoring...\n",
190427ee206SStephen Just 			__func__, data[9]);
19172fb4765SStephen Just 		break;
19272fb4765SStephen Just 	}
193427ee206SStephen Just }
194427ee206SStephen Just 
surface3_spi_irq_handler(int irq,void * dev_id)1954feacbc2SBenjamin Tissoires static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
1964feacbc2SBenjamin Tissoires {
1974feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data = dev_id;
1984feacbc2SBenjamin Tissoires 
1994feacbc2SBenjamin Tissoires 	if (surface3_spi_read(data))
2004feacbc2SBenjamin Tissoires 		return IRQ_HANDLED;
2014feacbc2SBenjamin Tissoires 
2024feacbc2SBenjamin Tissoires 	dev_dbg(&data->spi->dev, "%s received -> %*ph\n",
2034feacbc2SBenjamin Tissoires 		__func__, SURFACE3_PACKET_SIZE, data->rd_buf);
2044feacbc2SBenjamin Tissoires 	surface3_spi_process(data);
2054feacbc2SBenjamin Tissoires 
2064feacbc2SBenjamin Tissoires 	return IRQ_HANDLED;
2074feacbc2SBenjamin Tissoires }
2084feacbc2SBenjamin Tissoires 
surface3_spi_power(struct surface3_ts_data * data,bool on)2094feacbc2SBenjamin Tissoires static void surface3_spi_power(struct surface3_ts_data *data, bool on)
2104feacbc2SBenjamin Tissoires {
2114feacbc2SBenjamin Tissoires 	gpiod_set_value(data->gpiod_rst[0], on);
2124feacbc2SBenjamin Tissoires 	gpiod_set_value(data->gpiod_rst[1], on);
2134feacbc2SBenjamin Tissoires 	/* let the device settle a little */
2144feacbc2SBenjamin Tissoires 	msleep(20);
2154feacbc2SBenjamin Tissoires }
2164feacbc2SBenjamin Tissoires 
2174feacbc2SBenjamin Tissoires /**
2184feacbc2SBenjamin Tissoires  * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT
2194feacbc2SBenjamin Tissoires  *
220aea1f3ffSLee Jones  * @data: surface3_spi_ts_data pointer
2214feacbc2SBenjamin Tissoires  */
surface3_spi_get_gpio_config(struct surface3_ts_data * data)2224feacbc2SBenjamin Tissoires static int surface3_spi_get_gpio_config(struct surface3_ts_data *data)
2234feacbc2SBenjamin Tissoires {
2244feacbc2SBenjamin Tissoires 	struct device *dev;
2254feacbc2SBenjamin Tissoires 	struct gpio_desc *gpiod;
2264feacbc2SBenjamin Tissoires 	int i;
2274feacbc2SBenjamin Tissoires 
2284feacbc2SBenjamin Tissoires 	dev = &data->spi->dev;
2294feacbc2SBenjamin Tissoires 
2304feacbc2SBenjamin Tissoires 	/* Get the reset lines GPIO pin number */
2314feacbc2SBenjamin Tissoires 	for (i = 0; i < 2; i++) {
2324feacbc2SBenjamin Tissoires 		gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW);
233*d08149c1SKrzysztof Kozlowski 		if (IS_ERR(gpiod))
234*d08149c1SKrzysztof Kozlowski 			return dev_err_probe(dev, PTR_ERR(gpiod),
235*d08149c1SKrzysztof Kozlowski 					     "Failed to get power GPIO %d\n", i);
2364feacbc2SBenjamin Tissoires 
2374feacbc2SBenjamin Tissoires 		data->gpiod_rst[i] = gpiod;
2384feacbc2SBenjamin Tissoires 	}
2394feacbc2SBenjamin Tissoires 
2404feacbc2SBenjamin Tissoires 	return 0;
2414feacbc2SBenjamin Tissoires }
2424feacbc2SBenjamin Tissoires 
surface3_spi_create_touch_input(struct surface3_ts_data * data)243427ee206SStephen Just static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
2444feacbc2SBenjamin Tissoires {
2454feacbc2SBenjamin Tissoires 	struct input_dev *input;
2464feacbc2SBenjamin Tissoires 	int error;
2474feacbc2SBenjamin Tissoires 
2484feacbc2SBenjamin Tissoires 	input = devm_input_allocate_device(&data->spi->dev);
2494feacbc2SBenjamin Tissoires 	if (!input)
2504feacbc2SBenjamin Tissoires 		return -ENOMEM;
2514feacbc2SBenjamin Tissoires 
2524feacbc2SBenjamin Tissoires 	data->input_dev = input;
2534feacbc2SBenjamin Tissoires 
2544feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0);
2554feacbc2SBenjamin Tissoires 	input_abs_set_res(input, ABS_MT_POSITION_X, 40);
2564feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0);
2574feacbc2SBenjamin Tissoires 	input_abs_set_res(input, ABS_MT_POSITION_Y, 48);
2584feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0);
2594feacbc2SBenjamin Tissoires 	input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0);
2604feacbc2SBenjamin Tissoires 	input_mt_init_slots(input, 10, INPUT_MT_DIRECT);
2614feacbc2SBenjamin Tissoires 
2624feacbc2SBenjamin Tissoires 	input->name = "Surface3 SPI Capacitive TouchScreen";
2634feacbc2SBenjamin Tissoires 	input->phys = "input/ts";
2644feacbc2SBenjamin Tissoires 	input->id.bustype = BUS_SPI;
2654feacbc2SBenjamin Tissoires 	input->id.vendor = 0x045e;	/* Microsoft */
266427ee206SStephen Just 	input->id.product = 0x0001;
2674feacbc2SBenjamin Tissoires 	input->id.version = 0x0000;
2684feacbc2SBenjamin Tissoires 
2694feacbc2SBenjamin Tissoires 	error = input_register_device(input);
2704feacbc2SBenjamin Tissoires 	if (error) {
2714feacbc2SBenjamin Tissoires 		dev_err(&data->spi->dev,
2724feacbc2SBenjamin Tissoires 			"Failed to register input device: %d", error);
2734feacbc2SBenjamin Tissoires 		return error;
2744feacbc2SBenjamin Tissoires 	}
2754feacbc2SBenjamin Tissoires 
2764feacbc2SBenjamin Tissoires 	return 0;
2774feacbc2SBenjamin Tissoires }
2784feacbc2SBenjamin Tissoires 
surface3_spi_create_pen_input(struct surface3_ts_data * data)27972fb4765SStephen Just static int surface3_spi_create_pen_input(struct surface3_ts_data *data)
28072fb4765SStephen Just {
28172fb4765SStephen Just 	struct input_dev *input;
28272fb4765SStephen Just 	int error;
28372fb4765SStephen Just 
28472fb4765SStephen Just 	input = devm_input_allocate_device(&data->spi->dev);
28572fb4765SStephen Just 	if (!input)
28672fb4765SStephen Just 		return -ENOMEM;
28772fb4765SStephen Just 
28872fb4765SStephen Just 	data->pen_input_dev = input;
28972fb4765SStephen Just 	data->pen_tool = BTN_TOOL_PEN;
29072fb4765SStephen Just 
29172fb4765SStephen Just 	__set_bit(INPUT_PROP_DIRECT, input->propbit);
29272fb4765SStephen Just 	__set_bit(INPUT_PROP_POINTER, input->propbit);
29372fb4765SStephen Just 	input_set_abs_params(input, ABS_X, 0, 9600, 0, 0);
29472fb4765SStephen Just 	input_abs_set_res(input, ABS_X, 40);
29572fb4765SStephen Just 	input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0);
29672fb4765SStephen Just 	input_abs_set_res(input, ABS_Y, 48);
29772fb4765SStephen Just 	input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0);
29872fb4765SStephen Just 	input_set_capability(input, EV_KEY, BTN_TOUCH);
29972fb4765SStephen Just 	input_set_capability(input, EV_KEY, BTN_STYLUS);
30072fb4765SStephen Just 	input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
30172fb4765SStephen Just 	input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
30272fb4765SStephen Just 
30372fb4765SStephen Just 	input->name = "Surface3 SPI Pen Input";
30472fb4765SStephen Just 	input->phys = "input/ts";
30572fb4765SStephen Just 	input->id.bustype = BUS_SPI;
30672fb4765SStephen Just 	input->id.vendor = 0x045e;     /* Microsoft */
30772fb4765SStephen Just 	input->id.product = 0x0002;
30872fb4765SStephen Just 	input->id.version = 0x0000;
30972fb4765SStephen Just 
31072fb4765SStephen Just 	error = input_register_device(input);
31172fb4765SStephen Just 	if (error) {
31272fb4765SStephen Just 		dev_err(&data->spi->dev,
31372fb4765SStephen Just 			"Failed to register input device: %d", error);
31472fb4765SStephen Just 		return error;
31572fb4765SStephen Just 	}
31672fb4765SStephen Just 
31772fb4765SStephen Just 	return 0;
31872fb4765SStephen Just }
31972fb4765SStephen Just 
surface3_spi_probe(struct spi_device * spi)3204feacbc2SBenjamin Tissoires static int surface3_spi_probe(struct spi_device *spi)
3214feacbc2SBenjamin Tissoires {
3224feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data;
3234feacbc2SBenjamin Tissoires 	int error;
3244feacbc2SBenjamin Tissoires 
3254feacbc2SBenjamin Tissoires 	/* Set up SPI*/
3264feacbc2SBenjamin Tissoires 	spi->bits_per_word = 8;
3274feacbc2SBenjamin Tissoires 	spi->mode = SPI_MODE_0;
3284feacbc2SBenjamin Tissoires 	error = spi_setup(spi);
3294feacbc2SBenjamin Tissoires 	if (error)
3304feacbc2SBenjamin Tissoires 		return error;
3314feacbc2SBenjamin Tissoires 
3324feacbc2SBenjamin Tissoires 	data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL);
3334feacbc2SBenjamin Tissoires 	if (!data)
3344feacbc2SBenjamin Tissoires 		return -ENOMEM;
3354feacbc2SBenjamin Tissoires 
3364feacbc2SBenjamin Tissoires 	data->spi = spi;
3374feacbc2SBenjamin Tissoires 	spi_set_drvdata(spi, data);
3384feacbc2SBenjamin Tissoires 
3394feacbc2SBenjamin Tissoires 	error = surface3_spi_get_gpio_config(data);
3404feacbc2SBenjamin Tissoires 	if (error)
3414feacbc2SBenjamin Tissoires 		return error;
3424feacbc2SBenjamin Tissoires 
3434feacbc2SBenjamin Tissoires 	surface3_spi_power(data, true);
3444feacbc2SBenjamin Tissoires 	surface3_spi_power(data, false);
3454feacbc2SBenjamin Tissoires 	surface3_spi_power(data, true);
3464feacbc2SBenjamin Tissoires 
347427ee206SStephen Just 	error = surface3_spi_create_touch_input(data);
3484feacbc2SBenjamin Tissoires 	if (error)
3494feacbc2SBenjamin Tissoires 		return error;
3504feacbc2SBenjamin Tissoires 
35172fb4765SStephen Just 	error = surface3_spi_create_pen_input(data);
35272fb4765SStephen Just 	if (error)
35372fb4765SStephen Just 		return error;
35472fb4765SStephen Just 
3554feacbc2SBenjamin Tissoires 	error = devm_request_threaded_irq(&spi->dev, spi->irq,
3564feacbc2SBenjamin Tissoires 					  NULL, surface3_spi_irq_handler,
3574feacbc2SBenjamin Tissoires 					  IRQF_ONESHOT,
3584feacbc2SBenjamin Tissoires 					  "Surface3-irq", data);
3594feacbc2SBenjamin Tissoires 	if (error)
3604feacbc2SBenjamin Tissoires 		return error;
3614feacbc2SBenjamin Tissoires 
3624feacbc2SBenjamin Tissoires 	return 0;
3634feacbc2SBenjamin Tissoires }
3644feacbc2SBenjamin Tissoires 
surface3_spi_suspend(struct device * dev)365ea476f51SJonathan Cameron static int surface3_spi_suspend(struct device *dev)
3664feacbc2SBenjamin Tissoires {
3674feacbc2SBenjamin Tissoires 	struct spi_device *spi = to_spi_device(dev);
3684feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data = spi_get_drvdata(spi);
3694feacbc2SBenjamin Tissoires 
3704feacbc2SBenjamin Tissoires 	disable_irq(data->spi->irq);
3714feacbc2SBenjamin Tissoires 
3724feacbc2SBenjamin Tissoires 	surface3_spi_power(data, false);
3734feacbc2SBenjamin Tissoires 
3744feacbc2SBenjamin Tissoires 	return 0;
3754feacbc2SBenjamin Tissoires }
3764feacbc2SBenjamin Tissoires 
surface3_spi_resume(struct device * dev)377ea476f51SJonathan Cameron static int surface3_spi_resume(struct device *dev)
3784feacbc2SBenjamin Tissoires {
3794feacbc2SBenjamin Tissoires 	struct spi_device *spi = to_spi_device(dev);
3804feacbc2SBenjamin Tissoires 	struct surface3_ts_data *data = spi_get_drvdata(spi);
3814feacbc2SBenjamin Tissoires 
3824feacbc2SBenjamin Tissoires 	surface3_spi_power(data, true);
3834feacbc2SBenjamin Tissoires 
3844feacbc2SBenjamin Tissoires 	enable_irq(data->spi->irq);
3854feacbc2SBenjamin Tissoires 
3864feacbc2SBenjamin Tissoires 	return 0;
3874feacbc2SBenjamin Tissoires }
3884feacbc2SBenjamin Tissoires 
389ea476f51SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops,
3904feacbc2SBenjamin Tissoires 				surface3_spi_suspend,
3914feacbc2SBenjamin Tissoires 				surface3_spi_resume);
3924feacbc2SBenjamin Tissoires 
3934feacbc2SBenjamin Tissoires #ifdef CONFIG_ACPI
3944feacbc2SBenjamin Tissoires static const struct acpi_device_id surface3_spi_acpi_match[] = {
3954feacbc2SBenjamin Tissoires 	{ "MSHW0037", 0 },
3964feacbc2SBenjamin Tissoires 	{ }
3974feacbc2SBenjamin Tissoires };
3984feacbc2SBenjamin Tissoires MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match);
3994feacbc2SBenjamin Tissoires #endif
4004feacbc2SBenjamin Tissoires 
4014feacbc2SBenjamin Tissoires static struct spi_driver surface3_spi_driver = {
4024feacbc2SBenjamin Tissoires 	.driver = {
4034feacbc2SBenjamin Tissoires 		.name	= "Surface3-spi",
4044feacbc2SBenjamin Tissoires 		.acpi_match_table = ACPI_PTR(surface3_spi_acpi_match),
405ea476f51SJonathan Cameron 		.pm = pm_sleep_ptr(&surface3_spi_pm_ops),
4064feacbc2SBenjamin Tissoires 	},
4074feacbc2SBenjamin Tissoires 	.probe = surface3_spi_probe,
4084feacbc2SBenjamin Tissoires };
4094feacbc2SBenjamin Tissoires 
4104feacbc2SBenjamin Tissoires module_spi_driver(surface3_spi_driver);
4114feacbc2SBenjamin Tissoires 
4124feacbc2SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
4134feacbc2SBenjamin Tissoires MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver");
4144feacbc2SBenjamin Tissoires MODULE_LICENSE("GPL v2");
415