blob: 5babefef99a1eb7179a0330231748bac3572251d [file] [log] [blame]
Haibo Chen9a436d52015-09-05 11:31:21 -07001/*
2 * Freescale i.MX6UL touchscreen controller driver
3 *
4 * Copyright (C) 2015 Freescale Semiconductor, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/errno.h>
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/gpio/consumer.h>
15#include <linux/input.h>
16#include <linux/slab.h>
17#include <linux/completion.h>
18#include <linux/delay.h>
19#include <linux/of.h>
20#include <linux/interrupt.h>
21#include <linux/platform_device.h>
22#include <linux/clk.h>
23#include <linux/io.h>
24
25/* ADC configuration registers field define */
26#define ADC_AIEN (0x1 << 7)
27#define ADC_CONV_DISABLE 0x1F
Guy Shapiro031bfed2016-11-27 20:40:39 -080028#define ADC_AVGE (0x1 << 5)
Haibo Chen9a436d52015-09-05 11:31:21 -070029#define ADC_CAL (0x1 << 7)
30#define ADC_CALF 0x2
31#define ADC_12BIT_MODE (0x2 << 2)
Haibo Chen70f5a292016-11-30 09:02:06 -080032#define ADC_CONV_MODE_MASK (0x3 << 2)
Haibo Chen9a436d52015-09-05 11:31:21 -070033#define ADC_IPG_CLK 0x00
Haibo Chen70f5a292016-11-30 09:02:06 -080034#define ADC_INPUT_CLK_MASK 0x3
Haibo Chen9a436d52015-09-05 11:31:21 -070035#define ADC_CLK_DIV_8 (0x03 << 5)
Haibo Chen70f5a292016-11-30 09:02:06 -080036#define ADC_CLK_DIV_MASK (0x3 << 5)
Haibo Chen9a436d52015-09-05 11:31:21 -070037#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
Haibo Chen70f5a292016-11-30 09:02:06 -080038#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
Haibo Chen9a436d52015-09-05 11:31:21 -070039#define ADC_HARDWARE_TRIGGER (0x1 << 13)
Guy Shapiro031bfed2016-11-27 20:40:39 -080040#define ADC_AVGS_SHIFT 14
Haibo Chen70f5a292016-11-30 09:02:06 -080041#define ADC_AVGS_MASK (0x3 << 14)
Haibo Chen9a436d52015-09-05 11:31:21 -070042#define SELECT_CHANNEL_4 0x04
43#define SELECT_CHANNEL_1 0x01
44#define DISABLE_CONVERSION_INT (0x0 << 7)
45
46/* ADC registers */
47#define REG_ADC_HC0 0x00
48#define REG_ADC_HC1 0x04
49#define REG_ADC_HC2 0x08
50#define REG_ADC_HC3 0x0C
51#define REG_ADC_HC4 0x10
52#define REG_ADC_HS 0x14
53#define REG_ADC_R0 0x18
54#define REG_ADC_CFG 0x2C
55#define REG_ADC_GC 0x30
56#define REG_ADC_GS 0x34
57
58#define ADC_TIMEOUT msecs_to_jiffies(100)
59
60/* TSC registers */
61#define REG_TSC_BASIC_SETING 0x00
62#define REG_TSC_PRE_CHARGE_TIME 0x10
63#define REG_TSC_FLOW_CONTROL 0x20
64#define REG_TSC_MEASURE_VALUE 0x30
65#define REG_TSC_INT_EN 0x40
66#define REG_TSC_INT_SIG_EN 0x50
67#define REG_TSC_INT_STATUS 0x60
68#define REG_TSC_DEBUG_MODE 0x70
69#define REG_TSC_DEBUG_MODE2 0x80
70
71/* TSC configuration registers field define */
72#define DETECT_4_WIRE_MODE (0x0 << 4)
73#define AUTO_MEASURE 0x1
74#define MEASURE_SIGNAL 0x1
75#define DETECT_SIGNAL (0x1 << 4)
76#define VALID_SIGNAL (0x1 << 8)
77#define MEASURE_INT_EN 0x1
78#define MEASURE_SIG_EN 0x1
79#define VALID_SIG_EN (0x1 << 8)
80#define DE_GLITCH_2 (0x2 << 29)
81#define START_SENSE (0x1 << 12)
82#define TSC_DISABLE (0x1 << 16)
83#define DETECT_MODE 0x2
84
85struct imx6ul_tsc {
86 struct device *dev;
87 struct input_dev *input;
88 void __iomem *tsc_regs;
89 void __iomem *adc_regs;
90 struct clk *tsc_clk;
91 struct clk *adc_clk;
92 struct gpio_desc *xnur_gpio;
93
94 int measure_delay_time;
95 int pre_charge_time;
Guy Shapiro031bfed2016-11-27 20:40:39 -080096 int average_samples;
Haibo Chen9a436d52015-09-05 11:31:21 -070097
98 struct completion completion;
99};
100
101/*
102 * TSC module need ADC to get the measure value. So
103 * before config TSC, we should initialize ADC module.
104 */
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700105static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
Haibo Chen9a436d52015-09-05 11:31:21 -0700106{
107 int adc_hc = 0;
108 int adc_gc;
109 int adc_gs;
110 int adc_cfg;
111 int timeout;
112
113 reinit_completion(&tsc->completion);
114
115 adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
Haibo Chen70f5a292016-11-30 09:02:06 -0800116 adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
Haibo Chen9a436d52015-09-05 11:31:21 -0700117 adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
Haibo Chen70f5a292016-11-30 09:02:06 -0800118 adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
Haibo Chen9a436d52015-09-05 11:31:21 -0700119 adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
Haibo Chen70f5a292016-11-30 09:02:06 -0800120 if (tsc->average_samples) {
121 adc_cfg &= ~ADC_AVGS_MASK;
Guy Shapiro031bfed2016-11-27 20:40:39 -0800122 adc_cfg |= (tsc->average_samples - 1) << ADC_AVGS_SHIFT;
Haibo Chen70f5a292016-11-30 09:02:06 -0800123 }
Haibo Chen9a436d52015-09-05 11:31:21 -0700124 adc_cfg &= ~ADC_HARDWARE_TRIGGER;
125 writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
126
127 /* enable calibration interrupt */
128 adc_hc |= ADC_AIEN;
129 adc_hc |= ADC_CONV_DISABLE;
130 writel(adc_hc, tsc->adc_regs + REG_ADC_HC0);
131
132 /* start ADC calibration */
133 adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
134 adc_gc |= ADC_CAL;
Guy Shapiro031bfed2016-11-27 20:40:39 -0800135 if (tsc->average_samples)
136 adc_gc |= ADC_AVGE;
Haibo Chen9a436d52015-09-05 11:31:21 -0700137 writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
138
139 timeout = wait_for_completion_timeout
140 (&tsc->completion, ADC_TIMEOUT);
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700141 if (timeout == 0) {
Haibo Chen9a436d52015-09-05 11:31:21 -0700142 dev_err(tsc->dev, "Timeout for adc calibration\n");
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700143 return -ETIMEDOUT;
144 }
Haibo Chen9a436d52015-09-05 11:31:21 -0700145
146 adc_gs = readl(tsc->adc_regs + REG_ADC_GS);
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700147 if (adc_gs & ADC_CALF) {
Haibo Chen9a436d52015-09-05 11:31:21 -0700148 dev_err(tsc->dev, "ADC calibration failed\n");
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700149 return -EINVAL;
150 }
Haibo Chen9a436d52015-09-05 11:31:21 -0700151
152 /* TSC need the ADC work in hardware trigger */
153 adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
154 adc_cfg |= ADC_HARDWARE_TRIGGER;
155 writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700156
157 return 0;
Haibo Chen9a436d52015-09-05 11:31:21 -0700158}
159
160/*
161 * This is a TSC workaround. Currently TSC misconnect two
162 * ADC channels, this function remap channel configure for
163 * hardware trigger.
164 */
165static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
166{
167 int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
168
169 adc_hc0 = DISABLE_CONVERSION_INT;
170 writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
171
172 adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4;
173 writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1);
174
175 adc_hc2 = DISABLE_CONVERSION_INT;
176 writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2);
177
178 adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1;
179 writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3);
180
181 adc_hc4 = DISABLE_CONVERSION_INT;
182 writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4);
183}
184
185/*
186 * TSC setting, confige the pre-charge time and measure delay time.
187 * different touch screen may need different pre-charge time and
188 * measure delay time.
189 */
190static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
191{
192 int basic_setting = 0;
193 int start;
194
195 basic_setting |= tsc->measure_delay_time << 8;
196 basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
197 writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING);
198
199 writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
200
201 writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME);
202 writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN);
203 writel(MEASURE_SIG_EN | VALID_SIG_EN,
204 tsc->tsc_regs + REG_TSC_INT_SIG_EN);
205
206 /* start sense detection */
207 start = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
208 start |= START_SENSE;
209 start &= ~TSC_DISABLE;
210 writel(start, tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
211}
212
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700213static int imx6ul_tsc_init(struct imx6ul_tsc *tsc)
Haibo Chen9a436d52015-09-05 11:31:21 -0700214{
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700215 int err;
216
217 err = imx6ul_adc_init(tsc);
218 if (err)
219 return err;
Haibo Chen9a436d52015-09-05 11:31:21 -0700220 imx6ul_tsc_channel_config(tsc);
221 imx6ul_tsc_set(tsc);
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700222
223 return 0;
Haibo Chen9a436d52015-09-05 11:31:21 -0700224}
225
226static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc)
227{
228 int tsc_flow;
229 int adc_cfg;
230
231 /* TSC controller enters to idle status */
232 tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
233 tsc_flow |= TSC_DISABLE;
234 writel(tsc_flow, tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
235
236 /* ADC controller enters to stop mode */
237 adc_cfg = readl(tsc->adc_regs + REG_ADC_HC0);
238 adc_cfg |= ADC_CONV_DISABLE;
239 writel(adc_cfg, tsc->adc_regs + REG_ADC_HC0);
240}
241
242/* Delay some time (max 2ms), wait the pre-charge done. */
243static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
244{
245 unsigned long timeout = jiffies + msecs_to_jiffies(2);
246 int state_machine;
247 int debug_mode2;
248
249 do {
250 if (time_after(jiffies, timeout))
251 return false;
252
253 usleep_range(200, 400);
254 debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
255 state_machine = (debug_mode2 >> 20) & 0x7;
256 } while (state_machine != DETECT_MODE);
257
258 usleep_range(200, 400);
259 return true;
260}
261
262static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
263{
264 struct imx6ul_tsc *tsc = dev_id;
265 int status;
266 int value;
267 int x, y;
268 int start;
269
270 status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS);
271
272 /* write 1 to clear the bit measure-signal */
273 writel(MEASURE_SIGNAL | DETECT_SIGNAL,
274 tsc->tsc_regs + REG_TSC_INT_STATUS);
275
276 /* It's a HW self-clean bit. Set this bit and start sense detection */
277 start = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
278 start |= START_SENSE;
279 writel(start, tsc->tsc_regs + REG_TSC_FLOW_CONTROL);
280
281 if (status & MEASURE_SIGNAL) {
282 value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE);
283 x = (value >> 16) & 0x0fff;
284 y = value & 0x0fff;
285
286 /*
287 * In detect mode, we can get the xnur gpio value,
288 * otherwise assume contact is stiull active.
289 */
290 if (!tsc_wait_detect_mode(tsc) ||
291 gpiod_get_value_cansleep(tsc->xnur_gpio)) {
292 input_report_key(tsc->input, BTN_TOUCH, 1);
293 input_report_abs(tsc->input, ABS_X, x);
294 input_report_abs(tsc->input, ABS_Y, y);
295 } else {
296 input_report_key(tsc->input, BTN_TOUCH, 0);
297 }
298
299 input_sync(tsc->input);
300 }
301
302 return IRQ_HANDLED;
303}
304
305static irqreturn_t adc_irq_fn(int irq, void *dev_id)
306{
307 struct imx6ul_tsc *tsc = dev_id;
308 int coco;
309 int value;
310
311 coco = readl(tsc->adc_regs + REG_ADC_HS);
312 if (coco & 0x01) {
313 value = readl(tsc->adc_regs + REG_ADC_R0);
314 complete(&tsc->completion);
315 }
316
317 return IRQ_HANDLED;
318}
319
320static int imx6ul_tsc_open(struct input_dev *input_dev)
321{
322 struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
323 int err;
324
325 err = clk_prepare_enable(tsc->adc_clk);
326 if (err) {
327 dev_err(tsc->dev,
328 "Could not prepare or enable the adc clock: %d\n",
329 err);
330 return err;
331 }
332
333 err = clk_prepare_enable(tsc->tsc_clk);
334 if (err) {
335 dev_err(tsc->dev,
336 "Could not prepare or enable the tsc clock: %d\n",
337 err);
338 clk_disable_unprepare(tsc->adc_clk);
339 return err;
340 }
341
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700342 return imx6ul_tsc_init(tsc);
Haibo Chen9a436d52015-09-05 11:31:21 -0700343}
344
345static void imx6ul_tsc_close(struct input_dev *input_dev)
346{
347 struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
348
349 imx6ul_tsc_disable(tsc);
350
351 clk_disable_unprepare(tsc->tsc_clk);
352 clk_disable_unprepare(tsc->adc_clk);
353}
354
355static int imx6ul_tsc_probe(struct platform_device *pdev)
356{
357 struct device_node *np = pdev->dev.of_node;
358 struct imx6ul_tsc *tsc;
359 struct input_dev *input_dev;
360 struct resource *tsc_mem;
361 struct resource *adc_mem;
362 int err;
363 int tsc_irq;
364 int adc_irq;
365
Fabio Estevam5eab3cf2015-09-14 10:37:31 -0700366 tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
Haibo Chen9a436d52015-09-05 11:31:21 -0700367 if (!tsc)
368 return -ENOMEM;
369
370 input_dev = devm_input_allocate_device(&pdev->dev);
371 if (!input_dev)
372 return -ENOMEM;
373
Fabio Estevam002801f2015-09-14 10:37:55 -0700374 input_dev->name = "iMX6UL Touchscreen Controller";
Haibo Chen9a436d52015-09-05 11:31:21 -0700375 input_dev->id.bustype = BUS_HOST;
376
377 input_dev->open = imx6ul_tsc_open;
378 input_dev->close = imx6ul_tsc_close;
379
380 input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
381 input_set_abs_params(input_dev, ABS_X, 0, 0xFFF, 0, 0);
382 input_set_abs_params(input_dev, ABS_Y, 0, 0xFFF, 0, 0);
383
384 input_set_drvdata(input_dev, tsc);
385
386 tsc->dev = &pdev->dev;
387 tsc->input = input_dev;
388 init_completion(&tsc->completion);
389
390 tsc->xnur_gpio = devm_gpiod_get(&pdev->dev, "xnur", GPIOD_IN);
391 if (IS_ERR(tsc->xnur_gpio)) {
392 err = PTR_ERR(tsc->xnur_gpio);
393 dev_err(&pdev->dev,
394 "failed to request GPIO tsc_X- (xnur): %d\n", err);
395 return err;
396 }
397
398 tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
399 tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem);
400 if (IS_ERR(tsc->tsc_regs)) {
401 err = PTR_ERR(tsc->tsc_regs);
402 dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err);
403 return err;
404 }
405
406 adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
407 tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem);
408 if (IS_ERR(tsc->adc_regs)) {
409 err = PTR_ERR(tsc->adc_regs);
410 dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err);
411 return err;
412 }
413
414 tsc->tsc_clk = devm_clk_get(&pdev->dev, "tsc");
415 if (IS_ERR(tsc->tsc_clk)) {
416 err = PTR_ERR(tsc->tsc_clk);
417 dev_err(&pdev->dev, "failed getting tsc clock: %d\n", err);
418 return err;
419 }
420
421 tsc->adc_clk = devm_clk_get(&pdev->dev, "adc");
422 if (IS_ERR(tsc->adc_clk)) {
423 err = PTR_ERR(tsc->adc_clk);
424 dev_err(&pdev->dev, "failed getting adc clock: %d\n", err);
425 return err;
426 }
427
428 tsc_irq = platform_get_irq(pdev, 0);
429 if (tsc_irq < 0) {
430 dev_err(&pdev->dev, "no tsc irq resource?\n");
431 return tsc_irq;
432 }
433
434 adc_irq = platform_get_irq(pdev, 1);
Fabio Estevam3905de62015-09-14 10:37:08 -0700435 if (adc_irq < 0) {
Haibo Chen9a436d52015-09-05 11:31:21 -0700436 dev_err(&pdev->dev, "no adc irq resource?\n");
437 return adc_irq;
438 }
439
440 err = devm_request_threaded_irq(tsc->dev, tsc_irq,
441 NULL, tsc_irq_fn, IRQF_ONESHOT,
442 dev_name(&pdev->dev), tsc);
443 if (err) {
444 dev_err(&pdev->dev,
445 "failed requesting tsc irq %d: %d\n",
446 tsc_irq, err);
447 return err;
448 }
449
450 err = devm_request_irq(tsc->dev, adc_irq, adc_irq_fn, 0,
451 dev_name(&pdev->dev), tsc);
452 if (err) {
453 dev_err(&pdev->dev,
454 "failed requesting adc irq %d: %d\n",
455 adc_irq, err);
456 return err;
457 }
458
459 err = of_property_read_u32(np, "measure-delay-time",
460 &tsc->measure_delay_time);
461 if (err)
462 tsc->measure_delay_time = 0xffff;
463
464 err = of_property_read_u32(np, "pre-charge-time",
465 &tsc->pre_charge_time);
466 if (err)
467 tsc->pre_charge_time = 0xfff;
468
Guy Shapiro031bfed2016-11-27 20:40:39 -0800469 err = of_property_read_u32(np, "average-samples",
470 &tsc->average_samples);
471 if (err)
472 tsc->average_samples = 0;
473
474 if (tsc->average_samples > 4) {
475 dev_err(&pdev->dev, "average-samples (%u) must be [0-4]\n",
476 tsc->average_samples);
477 return -EINVAL;
478 }
479
Haibo Chen9a436d52015-09-05 11:31:21 -0700480 err = input_register_device(tsc->input);
481 if (err) {
482 dev_err(&pdev->dev,
483 "failed to register input device: %d\n", err);
484 return err;
485 }
486
487 platform_set_drvdata(pdev, tsc);
488 return 0;
489}
490
491static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
492{
493 struct platform_device *pdev = to_platform_device(dev);
494 struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
495 struct input_dev *input_dev = tsc->input;
496
497 mutex_lock(&input_dev->mutex);
498
499 if (input_dev->users) {
500 imx6ul_tsc_disable(tsc);
501
502 clk_disable_unprepare(tsc->tsc_clk);
503 clk_disable_unprepare(tsc->adc_clk);
504 }
505
506 mutex_unlock(&input_dev->mutex);
507
508 return 0;
509}
510
511static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
512{
513 struct platform_device *pdev = to_platform_device(dev);
514 struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
515 struct input_dev *input_dev = tsc->input;
516 int retval = 0;
517
518 mutex_lock(&input_dev->mutex);
519
520 if (input_dev->users) {
521 retval = clk_prepare_enable(tsc->adc_clk);
522 if (retval)
523 goto out;
524
525 retval = clk_prepare_enable(tsc->tsc_clk);
526 if (retval) {
527 clk_disable_unprepare(tsc->adc_clk);
528 goto out;
529 }
530
Fabio Estevam6cc527b2015-09-14 10:36:35 -0700531 retval = imx6ul_tsc_init(tsc);
Haibo Chen9a436d52015-09-05 11:31:21 -0700532 }
533
534out:
535 mutex_unlock(&input_dev->mutex);
536 return retval;
537}
538
539static SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops,
540 imx6ul_tsc_suspend, imx6ul_tsc_resume);
541
542static const struct of_device_id imx6ul_tsc_match[] = {
543 { .compatible = "fsl,imx6ul-tsc", },
544 { /* sentinel */ }
545};
546MODULE_DEVICE_TABLE(of, imx6ul_tsc_match);
547
548static struct platform_driver imx6ul_tsc_driver = {
549 .driver = {
550 .name = "imx6ul-tsc",
551 .of_match_table = imx6ul_tsc_match,
552 .pm = &imx6ul_tsc_pm_ops,
553 },
554 .probe = imx6ul_tsc_probe,
555};
556module_platform_driver(imx6ul_tsc_driver);
557
558MODULE_AUTHOR("Haibo Chen <haibo.chen@freescale.com>");
559MODULE_DESCRIPTION("Freescale i.MX6UL Touchscreen controller driver");
560MODULE_LICENSE("GPL v2");