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 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 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 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 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 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 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 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 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 * 220*aea1f3ffSLee Jones * @data: surface3_spi_ts_data pointer 2214feacbc2SBenjamin Tissoires */ 2224feacbc2SBenjamin Tissoires static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) 2234feacbc2SBenjamin Tissoires { 2244feacbc2SBenjamin Tissoires int error; 2254feacbc2SBenjamin Tissoires struct device *dev; 2264feacbc2SBenjamin Tissoires struct gpio_desc *gpiod; 2274feacbc2SBenjamin Tissoires int i; 2284feacbc2SBenjamin Tissoires 2294feacbc2SBenjamin Tissoires dev = &data->spi->dev; 2304feacbc2SBenjamin Tissoires 2314feacbc2SBenjamin Tissoires /* Get the reset lines GPIO pin number */ 2324feacbc2SBenjamin Tissoires for (i = 0; i < 2; i++) { 2334feacbc2SBenjamin Tissoires gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW); 2344feacbc2SBenjamin Tissoires if (IS_ERR(gpiod)) { 2354feacbc2SBenjamin Tissoires error = PTR_ERR(gpiod); 2364feacbc2SBenjamin Tissoires if (error != -EPROBE_DEFER) 2374feacbc2SBenjamin Tissoires dev_err(dev, 2384feacbc2SBenjamin Tissoires "Failed to get power GPIO %d: %d\n", 2394feacbc2SBenjamin Tissoires i, 2404feacbc2SBenjamin Tissoires error); 2414feacbc2SBenjamin Tissoires return error; 2424feacbc2SBenjamin Tissoires } 2434feacbc2SBenjamin Tissoires 2444feacbc2SBenjamin Tissoires data->gpiod_rst[i] = gpiod; 2454feacbc2SBenjamin Tissoires } 2464feacbc2SBenjamin Tissoires 2474feacbc2SBenjamin Tissoires return 0; 2484feacbc2SBenjamin Tissoires } 2494feacbc2SBenjamin Tissoires 250427ee206SStephen Just static int surface3_spi_create_touch_input(struct surface3_ts_data *data) 2514feacbc2SBenjamin Tissoires { 2524feacbc2SBenjamin Tissoires struct input_dev *input; 2534feacbc2SBenjamin Tissoires int error; 2544feacbc2SBenjamin Tissoires 2554feacbc2SBenjamin Tissoires input = devm_input_allocate_device(&data->spi->dev); 2564feacbc2SBenjamin Tissoires if (!input) 2574feacbc2SBenjamin Tissoires return -ENOMEM; 2584feacbc2SBenjamin Tissoires 2594feacbc2SBenjamin Tissoires data->input_dev = input; 2604feacbc2SBenjamin Tissoires 2614feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_POSITION_X, 0, 9600, 0, 0); 2624feacbc2SBenjamin Tissoires input_abs_set_res(input, ABS_MT_POSITION_X, 40); 2634feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 7200, 0, 0); 2644feacbc2SBenjamin Tissoires input_abs_set_res(input, ABS_MT_POSITION_Y, 48); 2654feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 1024, 0, 0); 2664feacbc2SBenjamin Tissoires input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 1024, 0, 0); 2674feacbc2SBenjamin Tissoires input_mt_init_slots(input, 10, INPUT_MT_DIRECT); 2684feacbc2SBenjamin Tissoires 2694feacbc2SBenjamin Tissoires input->name = "Surface3 SPI Capacitive TouchScreen"; 2704feacbc2SBenjamin Tissoires input->phys = "input/ts"; 2714feacbc2SBenjamin Tissoires input->id.bustype = BUS_SPI; 2724feacbc2SBenjamin Tissoires input->id.vendor = 0x045e; /* Microsoft */ 273427ee206SStephen Just input->id.product = 0x0001; 2744feacbc2SBenjamin Tissoires input->id.version = 0x0000; 2754feacbc2SBenjamin Tissoires 2764feacbc2SBenjamin Tissoires error = input_register_device(input); 2774feacbc2SBenjamin Tissoires if (error) { 2784feacbc2SBenjamin Tissoires dev_err(&data->spi->dev, 2794feacbc2SBenjamin Tissoires "Failed to register input device: %d", error); 2804feacbc2SBenjamin Tissoires return error; 2814feacbc2SBenjamin Tissoires } 2824feacbc2SBenjamin Tissoires 2834feacbc2SBenjamin Tissoires return 0; 2844feacbc2SBenjamin Tissoires } 2854feacbc2SBenjamin Tissoires 28672fb4765SStephen Just static int surface3_spi_create_pen_input(struct surface3_ts_data *data) 28772fb4765SStephen Just { 28872fb4765SStephen Just struct input_dev *input; 28972fb4765SStephen Just int error; 29072fb4765SStephen Just 29172fb4765SStephen Just input = devm_input_allocate_device(&data->spi->dev); 29272fb4765SStephen Just if (!input) 29372fb4765SStephen Just return -ENOMEM; 29472fb4765SStephen Just 29572fb4765SStephen Just data->pen_input_dev = input; 29672fb4765SStephen Just data->pen_tool = BTN_TOOL_PEN; 29772fb4765SStephen Just 29872fb4765SStephen Just __set_bit(INPUT_PROP_DIRECT, input->propbit); 29972fb4765SStephen Just __set_bit(INPUT_PROP_POINTER, input->propbit); 30072fb4765SStephen Just input_set_abs_params(input, ABS_X, 0, 9600, 0, 0); 30172fb4765SStephen Just input_abs_set_res(input, ABS_X, 40); 30272fb4765SStephen Just input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0); 30372fb4765SStephen Just input_abs_set_res(input, ABS_Y, 48); 30472fb4765SStephen Just input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0); 30572fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_TOUCH); 30672fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_STYLUS); 30772fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_TOOL_PEN); 30872fb4765SStephen Just input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER); 30972fb4765SStephen Just 31072fb4765SStephen Just input->name = "Surface3 SPI Pen Input"; 31172fb4765SStephen Just input->phys = "input/ts"; 31272fb4765SStephen Just input->id.bustype = BUS_SPI; 31372fb4765SStephen Just input->id.vendor = 0x045e; /* Microsoft */ 31472fb4765SStephen Just input->id.product = 0x0002; 31572fb4765SStephen Just input->id.version = 0x0000; 31672fb4765SStephen Just 31772fb4765SStephen Just error = input_register_device(input); 31872fb4765SStephen Just if (error) { 31972fb4765SStephen Just dev_err(&data->spi->dev, 32072fb4765SStephen Just "Failed to register input device: %d", error); 32172fb4765SStephen Just return error; 32272fb4765SStephen Just } 32372fb4765SStephen Just 32472fb4765SStephen Just return 0; 32572fb4765SStephen Just } 32672fb4765SStephen Just 3274feacbc2SBenjamin Tissoires static int surface3_spi_probe(struct spi_device *spi) 3284feacbc2SBenjamin Tissoires { 3294feacbc2SBenjamin Tissoires struct surface3_ts_data *data; 3304feacbc2SBenjamin Tissoires int error; 3314feacbc2SBenjamin Tissoires 3324feacbc2SBenjamin Tissoires /* Set up SPI*/ 3334feacbc2SBenjamin Tissoires spi->bits_per_word = 8; 3344feacbc2SBenjamin Tissoires spi->mode = SPI_MODE_0; 3354feacbc2SBenjamin Tissoires error = spi_setup(spi); 3364feacbc2SBenjamin Tissoires if (error) 3374feacbc2SBenjamin Tissoires return error; 3384feacbc2SBenjamin Tissoires 3394feacbc2SBenjamin Tissoires data = devm_kzalloc(&spi->dev, sizeof(*data), GFP_KERNEL); 3404feacbc2SBenjamin Tissoires if (!data) 3414feacbc2SBenjamin Tissoires return -ENOMEM; 3424feacbc2SBenjamin Tissoires 3434feacbc2SBenjamin Tissoires data->spi = spi; 3444feacbc2SBenjamin Tissoires spi_set_drvdata(spi, data); 3454feacbc2SBenjamin Tissoires 3464feacbc2SBenjamin Tissoires error = surface3_spi_get_gpio_config(data); 3474feacbc2SBenjamin Tissoires if (error) 3484feacbc2SBenjamin Tissoires return error; 3494feacbc2SBenjamin Tissoires 3504feacbc2SBenjamin Tissoires surface3_spi_power(data, true); 3514feacbc2SBenjamin Tissoires surface3_spi_power(data, false); 3524feacbc2SBenjamin Tissoires surface3_spi_power(data, true); 3534feacbc2SBenjamin Tissoires 354427ee206SStephen Just error = surface3_spi_create_touch_input(data); 3554feacbc2SBenjamin Tissoires if (error) 3564feacbc2SBenjamin Tissoires return error; 3574feacbc2SBenjamin Tissoires 35872fb4765SStephen Just error = surface3_spi_create_pen_input(data); 35972fb4765SStephen Just if (error) 36072fb4765SStephen Just return error; 36172fb4765SStephen Just 3624feacbc2SBenjamin Tissoires error = devm_request_threaded_irq(&spi->dev, spi->irq, 3634feacbc2SBenjamin Tissoires NULL, surface3_spi_irq_handler, 3644feacbc2SBenjamin Tissoires IRQF_ONESHOT, 3654feacbc2SBenjamin Tissoires "Surface3-irq", data); 3664feacbc2SBenjamin Tissoires if (error) 3674feacbc2SBenjamin Tissoires return error; 3684feacbc2SBenjamin Tissoires 3694feacbc2SBenjamin Tissoires return 0; 3704feacbc2SBenjamin Tissoires } 3714feacbc2SBenjamin Tissoires 3724feacbc2SBenjamin Tissoires static int __maybe_unused surface3_spi_suspend(struct device *dev) 3734feacbc2SBenjamin Tissoires { 3744feacbc2SBenjamin Tissoires struct spi_device *spi = to_spi_device(dev); 3754feacbc2SBenjamin Tissoires struct surface3_ts_data *data = spi_get_drvdata(spi); 3764feacbc2SBenjamin Tissoires 3774feacbc2SBenjamin Tissoires disable_irq(data->spi->irq); 3784feacbc2SBenjamin Tissoires 3794feacbc2SBenjamin Tissoires surface3_spi_power(data, false); 3804feacbc2SBenjamin Tissoires 3814feacbc2SBenjamin Tissoires return 0; 3824feacbc2SBenjamin Tissoires } 3834feacbc2SBenjamin Tissoires 3844feacbc2SBenjamin Tissoires static int __maybe_unused surface3_spi_resume(struct device *dev) 3854feacbc2SBenjamin Tissoires { 3864feacbc2SBenjamin Tissoires struct spi_device *spi = to_spi_device(dev); 3874feacbc2SBenjamin Tissoires struct surface3_ts_data *data = spi_get_drvdata(spi); 3884feacbc2SBenjamin Tissoires 3894feacbc2SBenjamin Tissoires surface3_spi_power(data, true); 3904feacbc2SBenjamin Tissoires 3914feacbc2SBenjamin Tissoires enable_irq(data->spi->irq); 3924feacbc2SBenjamin Tissoires 3934feacbc2SBenjamin Tissoires return 0; 3944feacbc2SBenjamin Tissoires } 3954feacbc2SBenjamin Tissoires 3964feacbc2SBenjamin Tissoires static SIMPLE_DEV_PM_OPS(surface3_spi_pm_ops, 3974feacbc2SBenjamin Tissoires surface3_spi_suspend, 3984feacbc2SBenjamin Tissoires surface3_spi_resume); 3994feacbc2SBenjamin Tissoires 4004feacbc2SBenjamin Tissoires #ifdef CONFIG_ACPI 4014feacbc2SBenjamin Tissoires static const struct acpi_device_id surface3_spi_acpi_match[] = { 4024feacbc2SBenjamin Tissoires { "MSHW0037", 0 }, 4034feacbc2SBenjamin Tissoires { } 4044feacbc2SBenjamin Tissoires }; 4054feacbc2SBenjamin Tissoires MODULE_DEVICE_TABLE(acpi, surface3_spi_acpi_match); 4064feacbc2SBenjamin Tissoires #endif 4074feacbc2SBenjamin Tissoires 4084feacbc2SBenjamin Tissoires static struct spi_driver surface3_spi_driver = { 4094feacbc2SBenjamin Tissoires .driver = { 4104feacbc2SBenjamin Tissoires .name = "Surface3-spi", 4114feacbc2SBenjamin Tissoires .acpi_match_table = ACPI_PTR(surface3_spi_acpi_match), 4124feacbc2SBenjamin Tissoires .pm = &surface3_spi_pm_ops, 4134feacbc2SBenjamin Tissoires }, 4144feacbc2SBenjamin Tissoires .probe = surface3_spi_probe, 4154feacbc2SBenjamin Tissoires }; 4164feacbc2SBenjamin Tissoires 4174feacbc2SBenjamin Tissoires module_spi_driver(surface3_spi_driver); 4184feacbc2SBenjamin Tissoires 4194feacbc2SBenjamin Tissoires MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); 4204feacbc2SBenjamin Tissoires MODULE_DESCRIPTION("Surface 3 SPI touchscreen driver"); 4214feacbc2SBenjamin Tissoires MODULE_LICENSE("GPL v2"); 422