aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Just <stephenjust@gmail.com>2016-05-27 19:29:39 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2016-05-27 19:33:34 -0400
commit72fb4765ac9eea56a94282f29cdc70706f21494e (patch)
treee7b29fa306d0d2f093d2042d2cd92f47783c0cfc
parent427ee20610a7c252e99d08e08e70a4203c6059d0 (diff)
Input: surface3_spi - add surface pen support for Surface 3
This change creates a second input device which will handle input from a Surface Pen. The Surface Pen supplies a different packet header than touch events, so it is simple to handle one or the other. This patch handles both the newer Surface Pen with one button, and the older variant with a second button to switch to Eraser mode. Signed-off-by: Stephen Just <stephenjust@gmail.com> Reviewed-and-tested-by: Benjamin Tissoires <benjamin.tissoires@redhat.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
-rw-r--r--drivers/input/touchscreen/surface3_spi.c114
1 files changed, 112 insertions, 2 deletions
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index e6cea7ed3d0e..e12fb9b63f31 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -27,11 +27,14 @@
27#define SURFACE3_PACKET_SIZE 264 27#define SURFACE3_PACKET_SIZE 264
28 28
29#define SURFACE3_REPORT_TOUCH 0xd2 29#define SURFACE3_REPORT_TOUCH 0xd2
30#define SURFACE3_REPORT_PEN 0x16
30 31
31struct surface3_ts_data { 32struct surface3_ts_data {
32 struct spi_device *spi; 33 struct spi_device *spi;
33 struct gpio_desc *gpiod_rst[2]; 34 struct gpio_desc *gpiod_rst[2];
34 struct input_dev *input_dev; 35 struct input_dev *input_dev;
36 struct input_dev *pen_input_dev;
37 int pen_tool;
35 38
36 u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned; 39 u8 rd_buf[SURFACE3_PACKET_SIZE] ____cacheline_aligned;
37}; 40};
@@ -48,6 +51,14 @@ struct surface3_ts_data_finger {
48 u32 padding; 51 u32 padding;
49} __packed; 52} __packed;
50 53
54struct surface3_ts_data_pen {
55 u8 status;
56 __le16 x;
57 __le16 y;
58 __le16 pressure;
59 u8 padding;
60} __packed;
61
51static int surface3_spi_read(struct surface3_ts_data *ts_data) 62static int surface3_spi_read(struct surface3_ts_data *ts_data)
52{ 63{
53 struct spi_device *spi = ts_data->spi; 64 struct spi_device *spi = ts_data->spi;
@@ -113,6 +124,53 @@ static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *dat
113 input_sync(ts_data->input_dev); 124 input_sync(ts_data->input_dev);
114} 125}
115 126
127static void surface3_spi_report_pen(struct surface3_ts_data *ts_data,
128 struct surface3_ts_data_pen *pen)
129{
130 struct input_dev *dev = ts_data->pen_input_dev;
131 int st = pen->status;
132 int prox = st & 0x01;
133 int rubber = st & 0x18;
134 int tool = (prox && rubber) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
135
136 /* fake proximity out to switch tools */
137 if (ts_data->pen_tool != tool) {
138 input_report_key(dev, ts_data->pen_tool, 0);
139 input_sync(dev);
140 ts_data->pen_tool = tool;
141 }
142
143 input_report_key(dev, BTN_TOUCH, st & 0x12);
144
145 input_report_key(dev, ts_data->pen_tool, prox);
146
147 if (st) {
148 input_report_key(dev,
149 BTN_STYLUS,
150 st & 0x04);
151
152 input_report_abs(dev,
153 ABS_X,
154 get_unaligned_le16(&pen->x));
155 input_report_abs(dev,
156 ABS_Y,
157 get_unaligned_le16(&pen->y));
158 input_report_abs(dev,
159 ABS_PRESSURE,
160 get_unaligned_le16(&pen->pressure));
161 }
162}
163
164static void surface3_spi_process_pen(struct surface3_ts_data *ts_data, u8 *data)
165{
166 struct surface3_ts_data_pen *pen;
167
168 pen = (struct surface3_ts_data_pen *)&data[15];
169
170 surface3_spi_report_pen(ts_data, pen);
171 input_sync(ts_data->pen_input_dev);
172}
173
116static void surface3_spi_process(struct surface3_ts_data *ts_data) 174static void surface3_spi_process(struct surface3_ts_data *ts_data)
117{ 175{
118 const char header[] = { 176 const char header[] = {
@@ -125,12 +183,19 @@ static void surface3_spi_process(struct surface3_ts_data *ts_data)
125 "%s header error: %*ph, ignoring...\n", 183 "%s header error: %*ph, ignoring...\n",
126 __func__, (int)sizeof(header), data); 184 __func__, (int)sizeof(header), data);
127 185
128 if (data[9] == SURFACE3_REPORT_TOUCH) 186 switch (data[9]) {
187 case SURFACE3_REPORT_TOUCH:
129 surface3_spi_process_touch(ts_data, data); 188 surface3_spi_process_touch(ts_data, data);
130 else 189 break;
190 case SURFACE3_REPORT_PEN:
191 surface3_spi_process_pen(ts_data, data);
192 break;
193 default:
131 dev_err(&ts_data->spi->dev, 194 dev_err(&ts_data->spi->dev,
132 "%s unknown packet type: %x, ignoring...\n", 195 "%s unknown packet type: %x, ignoring...\n",
133 __func__, data[9]); 196 __func__, data[9]);
197 break;
198 }
134} 199}
135 200
136static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id) 201static irqreturn_t surface3_spi_irq_handler(int irq, void *dev_id)
@@ -224,6 +289,47 @@ static int surface3_spi_create_touch_input(struct surface3_ts_data *data)
224 return 0; 289 return 0;
225} 290}
226 291
292static int surface3_spi_create_pen_input(struct surface3_ts_data *data)
293{
294 struct input_dev *input;
295 int error;
296
297 input = devm_input_allocate_device(&data->spi->dev);
298 if (!input)
299 return -ENOMEM;
300
301 data->pen_input_dev = input;
302 data->pen_tool = BTN_TOOL_PEN;
303
304 __set_bit(INPUT_PROP_DIRECT, input->propbit);
305 __set_bit(INPUT_PROP_POINTER, input->propbit);
306 input_set_abs_params(input, ABS_X, 0, 9600, 0, 0);
307 input_abs_set_res(input, ABS_X, 40);
308 input_set_abs_params(input, ABS_Y, 0, 7200, 0, 0);
309 input_abs_set_res(input, ABS_Y, 48);
310 input_set_abs_params(input, ABS_PRESSURE, 0, 1024, 0, 0);
311 input_set_capability(input, EV_KEY, BTN_TOUCH);
312 input_set_capability(input, EV_KEY, BTN_STYLUS);
313 input_set_capability(input, EV_KEY, BTN_TOOL_PEN);
314 input_set_capability(input, EV_KEY, BTN_TOOL_RUBBER);
315
316 input->name = "Surface3 SPI Pen Input";
317 input->phys = "input/ts";
318 input->id.bustype = BUS_SPI;
319 input->id.vendor = 0x045e; /* Microsoft */
320 input->id.product = 0x0002;
321 input->id.version = 0x0000;
322
323 error = input_register_device(input);
324 if (error) {
325 dev_err(&data->spi->dev,
326 "Failed to register input device: %d", error);
327 return error;
328 }
329
330 return 0;
331}
332
227static int surface3_spi_probe(struct spi_device *spi) 333static int surface3_spi_probe(struct spi_device *spi)
228{ 334{
229 struct surface3_ts_data *data; 335 struct surface3_ts_data *data;
@@ -255,6 +361,10 @@ static int surface3_spi_probe(struct spi_device *spi)
255 if (error) 361 if (error)
256 return error; 362 return error;
257 363
364 error = surface3_spi_create_pen_input(data);
365 if (error)
366 return error;
367
258 error = devm_request_threaded_irq(&spi->dev, spi->irq, 368 error = devm_request_threaded_irq(&spi->dev, spi->irq,
259 NULL, surface3_spi_irq_handler, 369 NULL, surface3_spi_irq_handler,
260 IRQF_ONESHOT, 370 IRQF_ONESHOT,