1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Driver for Pixcir I2C touchscreen controllers. |
4 | * |
5 | * Copyright (C) 2010-2011 Pixcir, Inc. |
6 | */ |
7 | |
8 | #include <asm/unaligned.h> |
9 | #include <linux/delay.h> |
10 | #include <linux/gpio/consumer.h> |
11 | #include <linux/i2c.h> |
12 | #include <linux/input.h> |
13 | #include <linux/input/mt.h> |
14 | #include <linux/input/touchscreen.h> |
15 | #include <linux/interrupt.h> |
16 | #include <linux/module.h> |
17 | #include <linux/of.h> |
18 | #include <linux/slab.h> |
19 | |
20 | #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ |
21 | |
22 | /* |
23 | * Register map |
24 | */ |
25 | #define PIXCIR_REG_POWER_MODE 51 |
26 | #define PIXCIR_REG_INT_MODE 52 |
27 | |
28 | /* |
29 | * Power modes: |
30 | * active: max scan speed |
31 | * idle: lower scan speed with automatic transition to active on touch |
32 | * halt: datasheet says sleep but this is more like halt as the chip |
33 | * clocks are cut and it can only be brought out of this mode |
34 | * using the RESET pin. |
35 | */ |
36 | enum pixcir_power_mode { |
37 | PIXCIR_POWER_ACTIVE, |
38 | PIXCIR_POWER_IDLE, |
39 | PIXCIR_POWER_HALT, |
40 | }; |
41 | |
42 | #define PIXCIR_POWER_MODE_MASK 0x03 |
43 | #define PIXCIR_POWER_ALLOW_IDLE (1UL << 2) |
44 | |
45 | /* |
46 | * Interrupt modes: |
47 | * periodical: interrupt is asserted periodicaly |
48 | * diff coordinates: interrupt is asserted when coordinates change |
49 | * level on touch: interrupt level asserted during touch |
50 | * pulse on touch: interrupt pulse asserted during touch |
51 | * |
52 | */ |
53 | enum pixcir_int_mode { |
54 | PIXCIR_INT_PERIODICAL, |
55 | PIXCIR_INT_DIFF_COORD, |
56 | PIXCIR_INT_LEVEL_TOUCH, |
57 | PIXCIR_INT_PULSE_TOUCH, |
58 | }; |
59 | |
60 | #define PIXCIR_INT_MODE_MASK 0x03 |
61 | #define PIXCIR_INT_ENABLE (1UL << 3) |
62 | #define PIXCIR_INT_POL_HIGH (1UL << 2) |
63 | |
64 | /** |
65 | * struct pixcir_i2c_chip_data - chip related data |
66 | * @max_fingers: Max number of fingers reported simultaneously by h/w |
67 | * @has_hw_ids: Hardware supports finger tracking IDs |
68 | * |
69 | */ |
70 | struct pixcir_i2c_chip_data { |
71 | u8 max_fingers; |
72 | bool has_hw_ids; |
73 | }; |
74 | |
75 | struct pixcir_i2c_ts_data { |
76 | struct i2c_client *client; |
77 | struct input_dev *input; |
78 | struct gpio_desc *gpio_attb; |
79 | struct gpio_desc *gpio_reset; |
80 | struct gpio_desc *gpio_enable; |
81 | struct gpio_desc *gpio_wake; |
82 | const struct pixcir_i2c_chip_data *chip; |
83 | struct touchscreen_properties prop; |
84 | bool running; |
85 | }; |
86 | |
87 | struct pixcir_report_data { |
88 | int num_touches; |
89 | struct input_mt_pos pos[PIXCIR_MAX_SLOTS]; |
90 | int ids[PIXCIR_MAX_SLOTS]; |
91 | }; |
92 | |
93 | static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, |
94 | struct pixcir_report_data *report) |
95 | { |
96 | u8 rdbuf[2 + PIXCIR_MAX_SLOTS * 5]; |
97 | u8 wrbuf[1] = { 0 }; |
98 | u8 *bufptr; |
99 | u8 touch; |
100 | int ret, i; |
101 | int readsize; |
102 | const struct pixcir_i2c_chip_data *chip = tsdata->chip; |
103 | |
104 | memset(report, 0, sizeof(struct pixcir_report_data)); |
105 | |
106 | i = chip->has_hw_ids ? 1 : 0; |
107 | readsize = 2 + tsdata->chip->max_fingers * (4 + i); |
108 | if (readsize > sizeof(rdbuf)) |
109 | readsize = sizeof(rdbuf); |
110 | |
111 | ret = i2c_master_send(client: tsdata->client, buf: wrbuf, count: sizeof(wrbuf)); |
112 | if (ret != sizeof(wrbuf)) { |
113 | dev_err(&tsdata->client->dev, |
114 | "%s: i2c_master_send failed(), ret=%d\n" , |
115 | __func__, ret); |
116 | return; |
117 | } |
118 | |
119 | ret = i2c_master_recv(client: tsdata->client, buf: rdbuf, count: readsize); |
120 | if (ret != readsize) { |
121 | dev_err(&tsdata->client->dev, |
122 | "%s: i2c_master_recv failed(), ret=%d\n" , |
123 | __func__, ret); |
124 | return; |
125 | } |
126 | |
127 | touch = rdbuf[0] & 0x7; |
128 | if (touch > tsdata->chip->max_fingers) |
129 | touch = tsdata->chip->max_fingers; |
130 | |
131 | report->num_touches = touch; |
132 | bufptr = &rdbuf[2]; |
133 | |
134 | for (i = 0; i < touch; i++) { |
135 | touchscreen_set_mt_pos(pos: &report->pos[i], prop: &tsdata->prop, |
136 | x: get_unaligned_le16(p: bufptr), |
137 | y: get_unaligned_le16(p: bufptr + 2)); |
138 | if (chip->has_hw_ids) { |
139 | report->ids[i] = bufptr[4]; |
140 | bufptr = bufptr + 5; |
141 | } else { |
142 | bufptr = bufptr + 4; |
143 | } |
144 | } |
145 | } |
146 | |
147 | static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, |
148 | struct pixcir_report_data *report) |
149 | { |
150 | int slots[PIXCIR_MAX_SLOTS]; |
151 | int n, i, slot; |
152 | struct device *dev = &ts->client->dev; |
153 | const struct pixcir_i2c_chip_data *chip = ts->chip; |
154 | |
155 | n = report->num_touches; |
156 | if (n > PIXCIR_MAX_SLOTS) |
157 | n = PIXCIR_MAX_SLOTS; |
158 | |
159 | if (!ts->chip->has_hw_ids) |
160 | input_mt_assign_slots(dev: ts->input, slots, pos: report->pos, num_pos: n, dmax: 0); |
161 | |
162 | for (i = 0; i < n; i++) { |
163 | if (chip->has_hw_ids) { |
164 | slot = input_mt_get_slot_by_key(dev: ts->input, |
165 | key: report->ids[i]); |
166 | if (slot < 0) { |
167 | dev_dbg(dev, "no free slot for id 0x%x\n" , |
168 | report->ids[i]); |
169 | continue; |
170 | } |
171 | } else { |
172 | slot = slots[i]; |
173 | } |
174 | |
175 | input_mt_slot(dev: ts->input, slot); |
176 | input_mt_report_slot_state(dev: ts->input, MT_TOOL_FINGER, active: true); |
177 | |
178 | input_report_abs(dev: ts->input, ABS_MT_POSITION_X, |
179 | value: report->pos[i].x); |
180 | input_report_abs(dev: ts->input, ABS_MT_POSITION_Y, |
181 | value: report->pos[i].y); |
182 | |
183 | dev_dbg(dev, "%d: slot %d, x %d, y %d\n" , |
184 | i, slot, report->pos[i].x, report->pos[i].y); |
185 | } |
186 | |
187 | input_mt_sync_frame(dev: ts->input); |
188 | input_sync(dev: ts->input); |
189 | } |
190 | |
191 | static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) |
192 | { |
193 | struct pixcir_i2c_ts_data *tsdata = dev_id; |
194 | struct pixcir_report_data report; |
195 | |
196 | while (tsdata->running) { |
197 | /* parse packet */ |
198 | pixcir_ts_parse(tsdata, report: &report); |
199 | |
200 | /* report it */ |
201 | pixcir_ts_report(ts: tsdata, report: &report); |
202 | |
203 | if (gpiod_get_value_cansleep(desc: tsdata->gpio_attb)) { |
204 | if (report.num_touches) { |
205 | /* |
206 | * Last report with no finger up? |
207 | * Do it now then. |
208 | */ |
209 | input_mt_sync_frame(dev: tsdata->input); |
210 | input_sync(dev: tsdata->input); |
211 | } |
212 | break; |
213 | } |
214 | |
215 | msleep(msecs: 20); |
216 | } |
217 | |
218 | return IRQ_HANDLED; |
219 | } |
220 | |
221 | static void pixcir_reset(struct pixcir_i2c_ts_data *tsdata) |
222 | { |
223 | if (!IS_ERR_OR_NULL(ptr: tsdata->gpio_reset)) { |
224 | gpiod_set_value_cansleep(desc: tsdata->gpio_reset, value: 1); |
225 | ndelay(100); /* datasheet section 1.2.3 says 80ns min. */ |
226 | gpiod_set_value_cansleep(desc: tsdata->gpio_reset, value: 0); |
227 | /* wait for controller ready. 100ms guess. */ |
228 | msleep(msecs: 100); |
229 | } |
230 | } |
231 | |
232 | static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, |
233 | enum pixcir_power_mode mode) |
234 | { |
235 | struct device *dev = &ts->client->dev; |
236 | int ret; |
237 | |
238 | if (mode == PIXCIR_POWER_ACTIVE || mode == PIXCIR_POWER_IDLE) { |
239 | if (ts->gpio_wake) |
240 | gpiod_set_value_cansleep(desc: ts->gpio_wake, value: 1); |
241 | } |
242 | |
243 | ret = i2c_smbus_read_byte_data(client: ts->client, PIXCIR_REG_POWER_MODE); |
244 | if (ret < 0) { |
245 | dev_err(dev, "%s: can't read reg %d : %d\n" , |
246 | __func__, PIXCIR_REG_POWER_MODE, ret); |
247 | return ret; |
248 | } |
249 | |
250 | ret &= ~PIXCIR_POWER_MODE_MASK; |
251 | ret |= mode; |
252 | |
253 | /* Always AUTO_IDLE */ |
254 | ret |= PIXCIR_POWER_ALLOW_IDLE; |
255 | |
256 | ret = i2c_smbus_write_byte_data(client: ts->client, PIXCIR_REG_POWER_MODE, value: ret); |
257 | if (ret < 0) { |
258 | dev_err(dev, "%s: can't write reg %d : %d\n" , |
259 | __func__, PIXCIR_REG_POWER_MODE, ret); |
260 | return ret; |
261 | } |
262 | |
263 | if (mode == PIXCIR_POWER_HALT) { |
264 | if (ts->gpio_wake) |
265 | gpiod_set_value_cansleep(desc: ts->gpio_wake, value: 0); |
266 | } |
267 | |
268 | return 0; |
269 | } |
270 | |
271 | /* |
272 | * Set the interrupt mode for the device i.e. ATTB line behaviour |
273 | * |
274 | * @polarity : 1 for active high, 0 for active low. |
275 | */ |
276 | static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts, |
277 | enum pixcir_int_mode mode, bool polarity) |
278 | { |
279 | struct device *dev = &ts->client->dev; |
280 | int ret; |
281 | |
282 | ret = i2c_smbus_read_byte_data(client: ts->client, PIXCIR_REG_INT_MODE); |
283 | if (ret < 0) { |
284 | dev_err(dev, "%s: can't read reg %d : %d\n" , |
285 | __func__, PIXCIR_REG_INT_MODE, ret); |
286 | return ret; |
287 | } |
288 | |
289 | ret &= ~PIXCIR_INT_MODE_MASK; |
290 | ret |= mode; |
291 | |
292 | if (polarity) |
293 | ret |= PIXCIR_INT_POL_HIGH; |
294 | else |
295 | ret &= ~PIXCIR_INT_POL_HIGH; |
296 | |
297 | ret = i2c_smbus_write_byte_data(client: ts->client, PIXCIR_REG_INT_MODE, value: ret); |
298 | if (ret < 0) { |
299 | dev_err(dev, "%s: can't write reg %d : %d\n" , |
300 | __func__, PIXCIR_REG_INT_MODE, ret); |
301 | return ret; |
302 | } |
303 | |
304 | return 0; |
305 | } |
306 | |
307 | /* |
308 | * Enable/disable interrupt generation |
309 | */ |
310 | static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable) |
311 | { |
312 | struct device *dev = &ts->client->dev; |
313 | int ret; |
314 | |
315 | ret = i2c_smbus_read_byte_data(client: ts->client, PIXCIR_REG_INT_MODE); |
316 | if (ret < 0) { |
317 | dev_err(dev, "%s: can't read reg %d : %d\n" , |
318 | __func__, PIXCIR_REG_INT_MODE, ret); |
319 | return ret; |
320 | } |
321 | |
322 | if (enable) |
323 | ret |= PIXCIR_INT_ENABLE; |
324 | else |
325 | ret &= ~PIXCIR_INT_ENABLE; |
326 | |
327 | ret = i2c_smbus_write_byte_data(client: ts->client, PIXCIR_REG_INT_MODE, value: ret); |
328 | if (ret < 0) { |
329 | dev_err(dev, "%s: can't write reg %d : %d\n" , |
330 | __func__, PIXCIR_REG_INT_MODE, ret); |
331 | return ret; |
332 | } |
333 | |
334 | return 0; |
335 | } |
336 | |
337 | static int pixcir_start(struct pixcir_i2c_ts_data *ts) |
338 | { |
339 | struct device *dev = &ts->client->dev; |
340 | int error; |
341 | |
342 | if (ts->gpio_enable) { |
343 | gpiod_set_value_cansleep(desc: ts->gpio_enable, value: 1); |
344 | msleep(msecs: 100); |
345 | } |
346 | |
347 | /* LEVEL_TOUCH interrupt with active low polarity */ |
348 | error = pixcir_set_int_mode(ts, mode: PIXCIR_INT_LEVEL_TOUCH, polarity: 0); |
349 | if (error) { |
350 | dev_err(dev, "Failed to set interrupt mode: %d\n" , error); |
351 | return error; |
352 | } |
353 | |
354 | ts->running = true; |
355 | mb(); /* Update status before IRQ can fire */ |
356 | |
357 | /* enable interrupt generation */ |
358 | error = pixcir_int_enable(ts, enable: true); |
359 | if (error) { |
360 | dev_err(dev, "Failed to enable interrupt generation: %d\n" , |
361 | error); |
362 | return error; |
363 | } |
364 | |
365 | return 0; |
366 | } |
367 | |
368 | static int pixcir_stop(struct pixcir_i2c_ts_data *ts) |
369 | { |
370 | int error; |
371 | |
372 | /* Disable interrupt generation */ |
373 | error = pixcir_int_enable(ts, enable: false); |
374 | if (error) { |
375 | dev_err(&ts->client->dev, |
376 | "Failed to disable interrupt generation: %d\n" , |
377 | error); |
378 | return error; |
379 | } |
380 | |
381 | /* Exit ISR if running, no more report parsing */ |
382 | ts->running = false; |
383 | mb(); /* update status before we synchronize irq */ |
384 | |
385 | /* Wait till running ISR is complete */ |
386 | synchronize_irq(irq: ts->client->irq); |
387 | |
388 | if (ts->gpio_enable) |
389 | gpiod_set_value_cansleep(desc: ts->gpio_enable, value: 0); |
390 | |
391 | return 0; |
392 | } |
393 | |
394 | static int pixcir_input_open(struct input_dev *dev) |
395 | { |
396 | struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); |
397 | |
398 | return pixcir_start(ts); |
399 | } |
400 | |
401 | static void pixcir_input_close(struct input_dev *dev) |
402 | { |
403 | struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev); |
404 | |
405 | pixcir_stop(ts); |
406 | } |
407 | |
408 | static int pixcir_i2c_ts_suspend(struct device *dev) |
409 | { |
410 | struct i2c_client *client = to_i2c_client(dev); |
411 | struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); |
412 | struct input_dev *input = ts->input; |
413 | int ret = 0; |
414 | |
415 | mutex_lock(&input->mutex); |
416 | |
417 | if (device_may_wakeup(dev: &client->dev)) { |
418 | if (!input_device_enabled(dev: input)) { |
419 | ret = pixcir_start(ts); |
420 | if (ret) { |
421 | dev_err(dev, "Failed to start\n" ); |
422 | goto unlock; |
423 | } |
424 | } |
425 | } else if (input_device_enabled(dev: input)) { |
426 | ret = pixcir_stop(ts); |
427 | } |
428 | |
429 | unlock: |
430 | mutex_unlock(lock: &input->mutex); |
431 | |
432 | return ret; |
433 | } |
434 | |
435 | static int pixcir_i2c_ts_resume(struct device *dev) |
436 | { |
437 | struct i2c_client *client = to_i2c_client(dev); |
438 | struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client); |
439 | struct input_dev *input = ts->input; |
440 | int ret = 0; |
441 | |
442 | mutex_lock(&input->mutex); |
443 | |
444 | if (device_may_wakeup(dev: &client->dev)) { |
445 | if (!input_device_enabled(dev: input)) { |
446 | ret = pixcir_stop(ts); |
447 | if (ret) { |
448 | dev_err(dev, "Failed to stop\n" ); |
449 | goto unlock; |
450 | } |
451 | } |
452 | } else if (input_device_enabled(dev: input)) { |
453 | ret = pixcir_start(ts); |
454 | } |
455 | |
456 | unlock: |
457 | mutex_unlock(lock: &input->mutex); |
458 | |
459 | return ret; |
460 | } |
461 | |
462 | static DEFINE_SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, |
463 | pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume); |
464 | |
465 | static int pixcir_i2c_ts_probe(struct i2c_client *client) |
466 | { |
467 | const struct i2c_device_id *id = i2c_client_get_device_id(client); |
468 | struct device *dev = &client->dev; |
469 | struct pixcir_i2c_ts_data *tsdata; |
470 | struct input_dev *input; |
471 | int error; |
472 | |
473 | tsdata = devm_kzalloc(dev, size: sizeof(*tsdata), GFP_KERNEL); |
474 | if (!tsdata) |
475 | return -ENOMEM; |
476 | |
477 | tsdata->chip = device_get_match_data(dev); |
478 | if (!tsdata->chip && id) |
479 | tsdata->chip = (const void *)id->driver_data; |
480 | if (!tsdata->chip) { |
481 | dev_err(dev, "can't locate chip data\n" ); |
482 | return -EINVAL; |
483 | } |
484 | |
485 | input = devm_input_allocate_device(dev); |
486 | if (!input) { |
487 | dev_err(dev, "Failed to allocate input device\n" ); |
488 | return -ENOMEM; |
489 | } |
490 | |
491 | tsdata->client = client; |
492 | tsdata->input = input; |
493 | |
494 | input->name = client->name; |
495 | input->id.bustype = BUS_I2C; |
496 | input->open = pixcir_input_open; |
497 | input->close = pixcir_input_close; |
498 | |
499 | input_set_capability(dev: input, EV_ABS, ABS_MT_POSITION_X); |
500 | input_set_capability(dev: input, EV_ABS, ABS_MT_POSITION_Y); |
501 | touchscreen_parse_properties(input, multitouch: true, prop: &tsdata->prop); |
502 | if (!input_abs_get_max(dev: input, ABS_MT_POSITION_X) || |
503 | !input_abs_get_max(dev: input, ABS_MT_POSITION_Y)) { |
504 | dev_err(dev, "Touchscreen size is not specified\n" ); |
505 | return -EINVAL; |
506 | } |
507 | |
508 | error = input_mt_init_slots(dev: input, num_slots: tsdata->chip->max_fingers, |
509 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); |
510 | if (error) { |
511 | dev_err(dev, "Error initializing Multi-Touch slots\n" ); |
512 | return error; |
513 | } |
514 | |
515 | input_set_drvdata(dev: input, data: tsdata); |
516 | |
517 | tsdata->gpio_attb = devm_gpiod_get(dev, con_id: "attb" , flags: GPIOD_IN); |
518 | if (IS_ERR(ptr: tsdata->gpio_attb)) |
519 | return dev_err_probe(dev, err: PTR_ERR(ptr: tsdata->gpio_attb), |
520 | fmt: "Failed to request ATTB gpio\n" ); |
521 | |
522 | tsdata->gpio_reset = devm_gpiod_get_optional(dev, con_id: "reset" , |
523 | flags: GPIOD_OUT_LOW); |
524 | if (IS_ERR(ptr: tsdata->gpio_reset)) |
525 | return dev_err_probe(dev, err: PTR_ERR(ptr: tsdata->gpio_reset), |
526 | fmt: "Failed to request RESET gpio\n" ); |
527 | |
528 | tsdata->gpio_wake = devm_gpiod_get_optional(dev, con_id: "wake" , |
529 | flags: GPIOD_OUT_HIGH); |
530 | if (IS_ERR(ptr: tsdata->gpio_wake)) |
531 | return dev_err_probe(dev, err: PTR_ERR(ptr: tsdata->gpio_wake), |
532 | fmt: "Failed to get wake gpio\n" ); |
533 | |
534 | tsdata->gpio_enable = devm_gpiod_get_optional(dev, con_id: "enable" , |
535 | flags: GPIOD_OUT_HIGH); |
536 | if (IS_ERR(ptr: tsdata->gpio_enable)) |
537 | return dev_err_probe(dev, err: PTR_ERR(ptr: tsdata->gpio_enable), |
538 | fmt: "Failed to get enable gpio\n" ); |
539 | |
540 | if (tsdata->gpio_enable) |
541 | msleep(msecs: 100); |
542 | |
543 | error = devm_request_threaded_irq(dev, irq: client->irq, NULL, thread_fn: pixcir_ts_isr, |
544 | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, |
545 | devname: client->name, dev_id: tsdata); |
546 | if (error) { |
547 | dev_err(dev, "failed to request irq %d\n" , client->irq); |
548 | return error; |
549 | } |
550 | |
551 | pixcir_reset(tsdata); |
552 | |
553 | /* Always be in IDLE mode to save power, device supports auto wake */ |
554 | error = pixcir_set_power_mode(ts: tsdata, mode: PIXCIR_POWER_IDLE); |
555 | if (error) { |
556 | dev_err(dev, "Failed to set IDLE mode\n" ); |
557 | return error; |
558 | } |
559 | |
560 | /* Stop device till opened */ |
561 | error = pixcir_stop(ts: tsdata); |
562 | if (error) |
563 | return error; |
564 | |
565 | error = input_register_device(input); |
566 | if (error) |
567 | return error; |
568 | |
569 | i2c_set_clientdata(client, data: tsdata); |
570 | |
571 | return 0; |
572 | } |
573 | |
574 | static const struct pixcir_i2c_chip_data pixcir_ts_data = { |
575 | .max_fingers = 2, |
576 | /* no hw id support */ |
577 | }; |
578 | |
579 | static const struct pixcir_i2c_chip_data pixcir_tangoc_data = { |
580 | .max_fingers = 5, |
581 | .has_hw_ids = true, |
582 | }; |
583 | |
584 | static const struct i2c_device_id pixcir_i2c_ts_id[] = { |
585 | { "pixcir_ts" , (unsigned long) &pixcir_ts_data }, |
586 | { "pixcir_tangoc" , (unsigned long) &pixcir_tangoc_data }, |
587 | { } |
588 | }; |
589 | MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id); |
590 | |
591 | #ifdef CONFIG_OF |
592 | static const struct of_device_id pixcir_of_match[] = { |
593 | { .compatible = "pixcir,pixcir_ts" , .data = &pixcir_ts_data }, |
594 | { .compatible = "pixcir,pixcir_tangoc" , .data = &pixcir_tangoc_data }, |
595 | { } |
596 | }; |
597 | MODULE_DEVICE_TABLE(of, pixcir_of_match); |
598 | #endif |
599 | |
600 | static struct i2c_driver pixcir_i2c_ts_driver = { |
601 | .driver = { |
602 | .name = "pixcir_ts" , |
603 | .pm = pm_sleep_ptr(&pixcir_dev_pm_ops), |
604 | .of_match_table = of_match_ptr(pixcir_of_match), |
605 | }, |
606 | .probe = pixcir_i2c_ts_probe, |
607 | .id_table = pixcir_i2c_ts_id, |
608 | }; |
609 | |
610 | module_i2c_driver(pixcir_i2c_ts_driver); |
611 | |
612 | MODULE_AUTHOR("Jianchun Bian <jcbian@pixcir.com.cn>, Dequan Meng <dqmeng@pixcir.com.cn>" ); |
613 | MODULE_DESCRIPTION("Pixcir I2C Touchscreen Driver" ); |
614 | MODULE_LICENSE("GPL" ); |
615 | |