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 29427ee206SStephen Just #define SURFACE3_REPORT_TOUCH 0xd2 3072fb4765SStephen Just #define SURFACE3_REPORT_PEN 0x16 31427ee206SStephen Just 324feacbc2SBenjamin Tissoires struct surface3_ts_data { 334feacbc2SBenjamin Tissoires struct spi_device *spi; 344feacbc2SBenjamin Tissoires struct gpio_desc *gpiod_rst[2]; 354feacbc2SBenjamin Tissoires struct input_dev *input_dev; 3672fb4765SStephen Just struct input_dev *pen_input_dev; 3772fb4765SStephen Just int pen_tool; 384feacbc2SBenjamin Tissoires 394feacbc2SBenjamin Tissoires u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned; 404feacbc2SBenjamin Tissoires }; 414feacbc2SBenjamin Tissoires 424feacbc2SBenjamin Tissoires struct surface3_ts_data_finger { 434feacbc2SBenjamin Tissoires u8 status; 444feacbc2SBenjamin Tissoires __le16 tracking_id; 454feacbc2SBenjamin Tissoires __le16 x; 464feacbc2SBenjamin Tissoires __le16 cx; 474feacbc2SBenjamin Tissoires __le16 y; 484feacbc2SBenjamin Tissoires __le16 cy; 494feacbc2SBenjamin Tissoires __le16 width; 504feacbc2SBenjamin Tissoires __le16 height; 514feacbc2SBenjamin Tissoires u32 padding; 524feacbc2SBenjamin Tissoires } __packed; 534feacbc2SBenjamin Tissoires 5472fb4765SStephen Just struct surface3_ts_data_pen { 5572fb4765SStephen Just u8 status; 5672fb4765SStephen Just __le16 x; 5772fb4765SStephen Just __le16 y; 5872fb4765SStephen Just __le16 pressure; 5972fb4765SStephen Just u8 padding; 6072fb4765SStephen Just } __packed; 6172fb4765SStephen Just 624feacbc2SBenjamin Tissoires static int surface3_spi_read(struct surface3_ts_data *ts_data) 634feacbc2SBenjamin Tissoires { 644feacbc2SBenjamin Tissoires struct spi_device *spi = ts_data->spi; 654feacbc2SBenjamin Tissoires 664feacbc2SBenjamin Tissoires memset(ts_data->rd_buf, 0, sizeof(ts_data->rd_buf)); 674feacbc2SBenjamin Tissoires return spi_read(spi, ts_data->rd_buf, sizeof(ts_data->rd_buf)); 684feacbc2SBenjamin Tissoires } 694feacbc2SBenjamin Tissoires 704feacbc2SBenjamin Tissoires static void surface3_spi_report_touch(struct surface3_ts_data *ts_data, 714feacbc2SBenjamin Tissoires struct surface3_ts_data_finger *finger) 724feacbc2SBenjamin Tissoires { 734feacbc2SBenjamin Tissoires int st = finger->status & 0x01; 744feacbc2SBenjamin Tissoires int slot; 754feacbc2SBenjamin Tissoires 764feacbc2SBenjamin Tissoires slot = input_mt_get_slot_by_key(ts_data->input_dev, 774feacbc2SBenjamin Tissoires get_unaligned_le16(&finger->tracking_id)); 784feacbc2SBenjamin Tissoires if (slot < 0) 794feacbc2SBenjamin Tissoires return; 804feacbc2SBenjamin Tissoires 814feacbc2SBenjamin Tissoires input_mt_slot(ts_data->input_dev, slot); 824feacbc2SBenjamin Tissoires input_mt_report_slot_state(ts_data->input_dev, MT_TOOL_FINGER, st); 834feacbc2SBenjamin Tissoires if (st) { 844feacbc2SBenjamin Tissoires input_report_abs(ts_data->input_dev, 854feacbc2SBenjamin Tissoires ABS_MT_POSITION_X, 864feacbc2SBenjamin Tissoires get_unaligned_le16(&finger->x)); 874feacbc2SBenjamin Tissoires input_report_abs(ts_data->input_dev, 884feacbc2SBenjamin Tissoires ABS_MT_POSITION_Y, 894feacbc2SBenjamin Tissoires get_unaligned_le16(&finger->y)); 904feacbc2SBenjamin Tissoires input_report_abs(ts_data->input_dev, 914feacbc2SBenjamin Tissoires ABS_MT_WIDTH_MAJOR, 924feacbc2SBenjamin Tissoires get_unaligned_le16(&finger->width)); 934feacbc2SBenjamin Tissoires input_report_abs(ts_data->input_dev, 944feacbc2SBenjamin Tissoires ABS_MT_WIDTH_MINOR, 954feacbc2SBenjamin Tissoires get_unaligned_le16(&finger->height)); 964feacbc2SBenjamin Tissoires } 974feacbc2SBenjamin Tissoires } 984feacbc2SBenjamin Tissoires 99427ee206SStephen Just static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data) 1004feacbc2SBenjamin Tissoires { 1014feacbc2SBenjamin Tissoires u16 timestamp; 1024feacbc2SBenjamin Tissoires unsigned int i; 1034feacbc2SBenjamin Tissoires timestamp = get_unaligned_le16(&data[15]); 1044feacbc2SBenjamin Tissoires 1054feacbc2SBenjamin Tissoires for (i = 0; i < 13; i++) { 1064feacbc2SBenjamin Tissoires struct surface3_ts_data_finger *finger; 1074feacbc2SBenjamin Tissoires 1084feacbc2SBenjamin Tissoires finger = (struct surface3_ts_data_finger *)&data[17 + 1094feacbc2SBenjamin Tissoires i * sizeof(struct surface3_ts_data_finger)]; 1104feacbc2SBenjamin Tissoires 1114feacbc2SBenjamin Tissoires /* 1124feacbc2SBenjamin Tissoires * When bit 5 of status is 1, it marks the end of the report: 1134feacbc2SBenjamin Tissoires * - touch present: 0xe7 1144feacbc2SBenjamin Tissoires * - touch released: 0xe4 1154feacbc2SBenjamin Tissoires * - nothing valuable: 0xff 1164feacbc2SBenjamin Tissoires */ 1174feacbc2SBenjamin Tissoires if (finger->status & 0x10) 1184feacbc2SBenjamin Tissoires break; 1194feacbc2SBenjamin Tissoires 1204feacbc2SBenjamin Tissoires surface3_spi_report_touch(ts_data, finger); 1214feacbc2SBenjamin Tissoires } 1224feacbc2SBenjamin Tissoires 1234feacbc2SBenjamin Tissoires input_mt_sync_frame(ts_data->input_dev); 1244feacbc2SBenjamin Tissoires input_sync(ts_data->input_dev); 1254feacbc2SBenjamin Tissoires } 1264feacbc2SBenjamin Tissoires 12772fb4765SStephen Just static void surface3_spi_report_pen(struct surface3_ts_data *ts_data, 12872fb4765SStephen Just struct surface3_ts_data_pen *pen) 12972fb4765SStephen Just { 13072fb4765SStephen Just struct input_dev *dev = ts_data->pen_input_dev; 13172fb4765SStephen Just int st = pen->status; 13272fb4765SStephen Just int prox = st & 0x01; 13372fb4765SStephen Just int rubber = st & 0x18; 13472fb4765SStephen Just int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; 13572fb4765SStephen Just 13672fb4765SStephen Just /* fake proximity out to switch tools */ 13772fb4765SStephen Just if (ts_data->pen_tool != tool) { 13872fb4765SStephen Just input_report_key(dev, ts_data->pen_tool, 0); 13972fb4765SStephen Just input_sync(dev); 14072fb4765SStephen Just ts_data->pen_tool = tool; 14172fb4765SStephen Just } 14272fb4765SStephen Just 14372fb4765SStephen Just input_report_key(dev, BTN_TOUCH, st & 0x12); 14472fb4765SStephen Just 14572fb4765SStephen Just input_report_key(dev, ts_data->pen_tool, prox); 14672fb4765SStephen Just 14772fb4765SStephen Just if (st) { 14872fb4765SStephen Just input_report_key(dev, 14972fb4765SStephen Just BTN_STYLUS, 15072fb4765SStephen Just st & 0x04); 15172fb4765SStephen Just 15272fb4765SStephen Just input_report_abs(dev, 15372fb4765SStephen Just ABS_X, 15472fb4765SStephen Just get_unaligned_le16(&pen->x)); 15572fb4765SStephen Just input_report_abs(dev, 15672fb4765SStephen Just ABS_Y, 15772fb4765SStephen Just get_unaligned_le16(&pen->y)); 15872fb4765SStephen Just input_report_abs(dev, 15972fb4765SStephen Just ABS_PRESSURE, 16072fb4765SStephen Just get_unaligned_le16(&pen->pressure)); 16172fb4765SStephen Just } 16272fb4765SStephen Just } 16372fb4765SStephen Just 16472fb4765SStephen Just static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data) 16572fb4765SStephen Just { 16672fb4765SStephen Just struct surface3_ts_data_pen *pen; 16772fb4765SStephen Just 16872fb4765SStephen Just pen = (struct surface3_ts_data_pen *)&data[15]; 16972fb4765SStephen Just 17072fb4765SStephen Just surface3_spi_report_pen(ts_data, pen); 17172fb4765SStephen Just input_sync(ts_data->pen_input_dev); 17272fb4765SStephen Just } 17372fb4765SStephen Just 174427ee206SStephen Just static void surface3_spi_process(struct surface3_ts_data *ts_data) 175427ee206SStephen Just { 176*023c437aSColin Ian King static const char header[] = { 177427ee206SStephen Just 0xff, 0xff, 0xff, 0xff, 0xa5, 0x5a, 0xe7, 0x7e, 0x01 178427ee206SStephen Just }; 179427ee206SStephen Just u8 *data = ts_data->rd_buf; 180427ee206SStephen Just 181427ee206SStephen Just if (memcmp(header, data, sizeof(header))) 182427ee206SStephen Just dev_err(&ts_data->spi->dev, 183427ee206SStephen Just "%s header error: %*ph, ignoring...\n", 184427ee206SStephen Just __func__, (int)sizeof(header), data); 185427ee206SStephen Just 18672fb4765SStephen Just switch (data[9]) { 18772fb4765SStephen Just case SURFACE3_REPORT_TOUCH: 188427ee206SStephen Just surface3_spi_process_touch(ts_data, data); 18972fb4765SStephen Just break; 19072fb4765SStephen Just case SURFACE3_REPORT_PEN: 19172fb4765SStephen Just surface3_spi_process_pen(ts_data, data); 19272fb4765SStephen Just break; 19372fb4765SStephen Just default: 194427ee206SStephen Just dev_err(&ts_data->spi->dev, 195427ee206SStephen Just "%s unknown packet type: %x, ignoring...\n", 196427ee206SStephen Just __func__, data[9]); 19772fb4765SStephen Just break; 19872fb4765SStephen Just } 199427ee206SStephen Just } 200427ee206SStephen Just 2014feacbc2SBenjamin Tissoires static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id) 2024feacbc2SBenjamin Tissoires { 2034feacbc2SBenjamin Tissoires struct surface3_ts_data *data = dev_id; 2044feacbc2SBenjamin Tissoires 2054feacbc2SBenjamin Tissoires if (surface3_spi_read(data)) 2064feacbc2SBenjamin Tissoires return IRQ_HANDLED; 2074feacbc2SBenjamin Tissoires 2084feacbc2SBenjamin Tissoires dev_dbg(&data->spi->dev, "%s received -> %*ph\n", 2094feacbc2SBenjamin Tissoires __func__, SURFACE3_PACKET_SIZE, data->rd_buf); 2104feacbc2SBenjamin Tissoires surface3_spi_process(data); 2114feacbc2SBenjamin Tissoires 2124feacbc2SBenjamin Tissoires return IRQ_HANDLED; 2134feacbc2SBenjamin Tissoires } 2144feacbc2SBenjamin Tissoires 2154feacbc2SBenjamin Tissoires static void surface3_spi_power(struct surface3_ts_data *data, bool on) 2164feacbc2SBenjamin Tissoires { 2174feacbc2SBenjamin Tissoires gpiod_set_value(data->gpiod_rst[0], on); 2184feacbc2SBenjamin Tissoires gpiod_set_value(data->gpiod_rst[1], on); 2194feacbc2SBenjamin Tissoires /* let the device settle a little */ 2204feacbc2SBenjamin Tissoires msleep(20); 2214feacbc2SBenjamin Tissoires } 2224feacbc2SBenjamin Tissoires 2234feacbc2SBenjamin Tissoires /** 2244feacbc2SBenjamin Tissoires * surface3_spi_get_gpio_config - Get GPIO config from ACPI/DT 2254feacbc2SBenjamin Tissoires * 2264feacbc2SBenjamin Tissoires * @ts: surface3_spi_ts_data pointer 2274feacbc2SBenjamin Tissoires */ 2284feacbc2SBenjamin Tissoires static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) 2294feacbc2SBenjamin Tissoires { 2304feacbc2SBenjamin Tissoires int error; 2314feacbc2SBenjamin Tissoires struct device *dev; 2324feacbc2SBenjamin Tissoires struct gpio_desc *gpiod; 2334feacbc2SBenjamin Tissoires int i; 2344feacbc2SBenjamin Tissoires 2354feacbc2SBenjamin Tissoires dev = &data->spi->dev; 2364feacbc2SBenjamin Tissoires 2374feacbc2SBenjamin Tissoires /* Get the reset lines GPIO pin number */ 2384feacbc2SBenjamin Tissoires for (i = 0; i < 2; i++) { 2394feacbc2SBenjamin Tissoires gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW); 2404feacbc2SBenjamin Tissoires if (IS_ERR(gpiod)) { 2414feacbc2SBenjamin Tissoires error = PTR_ERR(gpiod); 2424feacbc2SBenjamin Tissoires if (error != -EPROBE_DEFER) 2434feacbc2SBenjamin Tissoires dev_err(dev, 2444feacbc2SBenjamin Tissoires "Failed to get power GPIO %d: %d\n", 2454feacbc2SBenjamin Tissoires i, 2464feacbc2SBenjamin Tissoires error); 2474feacbc2SBenjamin Tissoires return error; 2484feacbc2SBenjamin Tissoires } 2494feacbc2SBenjamin Tissoires 2504feacbc2SBenjamin Tissoires data->gpiod_rst[i] = gpiod; 2514feacbc2SBenjamin Tissoires } 2524feacbc2SBenjamin Tissoires 2534feacbc2SBenjamin Tissoires return 0; 2544feacbc2SBenjamin Tissoires } 2554feacbc2SBenjamin Tissoires 256427ee206SStephen Just static int surface3_spi_create_touch_input(struct surface3_ts_data *data) 2574feacbc2SBenjamin Tissoires { 2584feacbc2SBenjamin Tissoires struct input_dev *input; 2594feacbc2SBenjamin Tissoires int error; 2604feacbc2SBenjamin Tissoires 2614feacbc2SBenjamin Tissoires input = devm_input_allocate_device(&data->spi->dev); 2624feacbc2SBenjamin Tissoires if (!input) 2634feacbc2SBenjamin Tissoires return -ENOMEM; 2644feacbc2SBenjamin Tissoires 2654feacbc2SBenjamin Tissoires data->input_dev = input; 2664feacbc2SBenjamin Tissoires 2674feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0); 2684feacbc2SBenjamin Tissoires input_abs_set_res(input, ABS_MT_POSITION_X, 40); 2694feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0); 2704feacbc2SBenjamin Tissoires input_abs_set_res(input, ABS_MT_POSITION_Y, 48); 2714feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0); 2724feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0); 2734feacbc2SBenjamin Tissoires input_mt_init_slots(input, 10, INPUT_MT_DIRECT); 2744feacbc2SBenjamin Tissoires 2754feacbc2SBenjamin Tissoires input->name = "Surface3 SPI Capacitive TouchScreen"; 2764feacbc2SBenjamin Tissoires input->phys = "input/ts"; 2774feacbc2SBenjamin Tissoires input->id.bustype = BUS_SPI; 2784feacbc2SBenjamin Tissoires input->id.vendor = 0x045e; /* Microsoft */ 279427ee206SStephen Just input->id.product = 0x0001; 2804feacbc2SBenjamin Tissoires input->id.version = 0x0000; 2814feacbc2SBenjamin Tissoires 2824feacbc2SBenjamin Tissoires error = input_register_device(input); 2834feacbc2SBenjamin Tissoires if (error) { 2844feacbc2SBenjamin Tissoires dev_err(&data->spi->dev, 2854feacbc2SBenjamin Tissoires "Failed to register input device: %d", error); 2864feacbc2SBenjamin Tissoires return error; 2874feacbc2SBenjamin Tissoires } 2884feacbc2SBenjamin Tissoires 2894feacbc2SBenjamin Tissoires return 0; 2904feacbc2SBenjamin Tissoires } 2914feacbc2SBenjamin Tissoires 29272fb4765SStephen Just static int surface3_spi_create_pen_input(struct surface3_ts_data *data) 29372fb4765SStephen Just { 29472fb4765SStephen Just struct input_dev *input; 29572fb4765SStephen Just int error; 29672fb4765SStephen Just 29772fb4765SStephen Just input = devm_input_allocate_device(&data->spi->dev); 29872fb4765SStephen Just if (!input) 29972fb4765SStephen Just return -ENOMEM; 30072fb4765SStephen Just 30172fb4765SStephen Just data->pen_input_dev = input; 30272fb4765SStephen Just data->pen_tool = BTN_TOOL_PEN; 30372fb4765SStephen Just 30472fb4765SStephen Just __set_bit(INPUT_PROP_DIRECT, input->propbit); 30572fb4765SStephen Just __set_bit(INPUT_PROP_POINTER, input->propbit); 30672fb4765SStephen Just input_set_abs_params(input, ABS_X, 0, 9600, 0, 0); 30772fb4765SStephen Just input_abs_set_res(input, ABS_X, 40); 30872fb4765SStephen Just input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0); 30972fb4765SStephen Just input_abs_set_res(input, ABS_Y, 48); 31072fb4765SStephen Just input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0); 31172fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_TOUCH); 31272fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_STYLUS); 31372fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_TOOL_PEN); 31472fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER); 31572fb4765SStephen Just 31672fb4765SStephen Just input->name = "Surface3 SPI Pen Input"; 31772fb4765SStephen Just input->phys = "input/ts"; 31872fb4765SStephen Just input->id.bustype = BUS_SPI; 31972fb4765SStephen Just input->id.vendor = 0x045e; /* Microsoft */ 32072fb4765SStephen Just input->id.product = 0x0002; 32172fb4765SStephen Just input->id.version = 0x0000; 32272fb4765SStephen Just 32372fb4765SStephen Just error = input_register_device(input); 32472fb4765SStephen Just if (error) { 32572fb4765SStephen Just dev_err(&data->spi->dev, 32672fb4765SStephen Just "Failed to register input device: %d", error); 32772fb4765SStephen Just return error; 32872fb4765SStephen Just } 32972fb4765SStephen Just 33072fb4765SStephen Just return 0; 33172fb4765SStephen Just } 33272fb4765SStephen Just 3334feacbc2SBenjamin Tissoires static int surface3_spi_probe(struct spi_device *spi) 3344feacbc2SBenjamin Tissoires { 3354feacbc2SBenjamin Tissoires struct surface3_ts_data *data; 3364feacbc2SBenjamin Tissoires int error; 3374feacbc2SBenjamin Tissoires 3384feacbc2SBenjamin Tissoires /* Set up SPI*/ 3394feacbc2SBenjamin Tissoires spi->bits_per_word = 8; 3404feacbc2SBenjamin Tissoires spi->mode = SPI_MODE_0; 3414feacbc2SBenjamin Tissoires error = spi_setup(spi); 3424feacbc2SBenjamin Tissoires if (error) 3434feacbc2SBenjamin Tissoires return error; 3444feacbc2SBenjamin Tissoires 3454feacbc2SBenjamin Tissoires data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL); 3464feacbc2SBenjamin Tissoires if (!data) 3474feacbc2SBenjamin Tissoires return -ENOMEM; 3484feacbc2SBenjamin Tissoires 3494feacbc2SBenjamin Tissoires data->spi = spi; 3504feacbc2SBenjamin Tissoires spi_set_drvdata(spi, data); 3514feacbc2SBenjamin Tissoires 3524feacbc2SBenjamin Tissoires error = surface3_spi_get_gpio_config(data); 3534feacbc2SBenjamin Tissoires if (error) 3544feacbc2SBenjamin Tissoires return error; 3554feacbc2SBenjamin Tissoires 3564feacbc2SBenjamin Tissoires surface3_spi_power(data, true); 3574feacbc2SBenjamin Tissoires surface3_spi_power(data, false); 3584feacbc2SBenjamin Tissoires surface3_spi_power(data, true); 3594feacbc2SBenjamin Tissoires 360427ee206SStephen Just error = surface3_spi_create_touch_input(data); 3614feacbc2SBenjamin Tissoires if (error) 3624feacbc2SBenjamin Tissoires return error; 3634feacbc2SBenjamin Tissoires 36472fb4765SStephen Just error = surface3_spi_create_pen_input(data); 36572fb4765SStephen Just if (error) 36672fb4765SStephen Just return error; 36772fb4765SStephen Just 3684feacbc2SBenjamin Tissoires error = devm_request_threaded_irq(&spi->dev, spi->irq, 3694feacbc2SBenjamin Tissoires NULL, surface3_spi_irq_handler, 3704feacbc2SBenjamin Tissoires IRQF_ONESHOT, 3714feacbc2SBenjamin Tissoires "Surface3-irq", data); 3724feacbc2SBenjamin Tissoires if (error) 3734feacbc2SBenjamin Tissoires return error; 3744feacbc2SBenjamin Tissoires 3754feacbc2SBenjamin Tissoires return 0; 3764feacbc2SBenjamin Tissoires } 3774feacbc2SBenjamin Tissoires 3784feacbc2SBenjamin Tissoires static int __maybe_unused surface3_spi_suspend(struct device *dev) 3794feacbc2SBenjamin Tissoires { 3804feacbc2SBenjamin Tissoires struct spi_device *spi = to_spi_device(dev); 3814feacbc2SBenjamin Tissoires struct surface3_ts_data *data = spi_get_drvdata(spi); 3824feacbc2SBenjamin Tissoires 3834feacbc2SBenjamin Tissoires disable_irq(data->spi->irq); 3844feacbc2SBenjamin Tissoires 3854feacbc2SBenjamin Tissoires surface3_spi_power(data, false); 3864feacbc2SBenjamin Tissoires 3874feacbc2SBenjamin Tissoires return 0; 3884feacbc2SBenjamin Tissoires } 3894feacbc2SBenjamin Tissoires 3904feacbc2SBenjamin Tissoires static int __maybe_unused surface3_spi_resume(struct device *dev) 3914feacbc2SBenjamin Tissoires { 3924feacbc2SBenjamin Tissoires struct spi_device *spi = to_spi_device(dev); 3934feacbc2SBenjamin Tissoires struct surface3_ts_data *data = spi_get_drvdata(spi); 3944feacbc2SBenjamin Tissoires 3954feacbc2SBenjamin Tissoires surface3_spi_power(data, true); 3964feacbc2SBenjamin Tissoires 3974feacbc2SBenjamin Tissoires enable_irq(data->spi->irq); 3984feacbc2SBenjamin Tissoires 3994feacbc2SBenjamin Tissoires return 0; 4004feacbc2SBenjamin Tissoires } 4014feacbc2SBenjamin Tissoires 4024feacbc2SBenjamin Tissoires static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops, 4034feacbc2SBenjamin Tissoires surface3_spi_suspend, 4044feacbc2SBenjamin Tissoires surface3_spi_resume); 4054feacbc2SBenjamin Tissoires 4064feacbc2SBenjamin Tissoires #ifdef CONFIG_ACPI 4074feacbc2SBenjamin Tissoires static const struct acpi_device_id surface3_spi_acpi_match[] = { 4084feacbc2SBenjamin Tissoires { "MSHW0037", 0 }, 4094feacbc2SBenjamin Tissoires { } 4104feacbc2SBenjamin Tissoires }; 4114feacbc2SBenjamin Tissoires MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match); 4124feacbc2SBenjamin Tissoires #endif 4134feacbc2SBenjamin Tissoires 4144feacbc2SBenjamin Tissoires static struct spi_driver surface3_spi_driver = { 4154feacbc2SBenjamin Tissoires .driver = { 4164feacbc2SBenjamin Tissoires .name = "Surface3-spi", 4174feacbc2SBenjamin Tissoires .acpi_match_table = ACPI_PTR(surface3_spi_acpi_match), 4184feacbc2SBenjamin Tissoires .pm = &surface3_spi_pm_ops, 4194feacbc2SBenjamin Tissoires }, 4204feacbc2SBenjamin Tissoires .probe = surface3_spi_probe, 4214feacbc2SBenjamin Tissoires }; 4224feacbc2SBenjamin Tissoires 4234feacbc2SBenjamin Tissoires module_spi_driver(surface3_spi_driver); 4244feacbc2SBenjamin Tissoires 4254feacbc2SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <[email protected]>"); 4264feacbc2SBenjamin Tissoires MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver"); 4274feacbc2SBenjamin Tissoires MODULE_LICENSE("GPL v2"); 428