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