Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / input / touchscreen / s3c2410_ts.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Samsung S3C24XX touchscreen driver
4  *
5  * Copyright 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
6  * Copyright 2008 Ben Dooks <ben-linux@fluff.org>
7  * Copyright 2009 Simtec Electronics <linux@simtec.co.uk>
8  *
9  * Additional work by Herbert Pƶtzl <herbert@13thfloor.at> and
10  * Harald Welte <laforge@openmoko.org>
11  */
12
13 #include <linux/errno.h>
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/gpio.h>
17 #include <linux/input.h>
18 #include <linux/delay.h>
19 #include <linux/interrupt.h>
20 #include <linux/platform_device.h>
21 #include <linux/clk.h>
22 #include <linux/io.h>
23
24 #include <plat/adc.h>
25 #include <plat/regs-adc.h>
26 #include <linux/platform_data/touchscreen-s3c2410.h>
27
28 #define TSC_SLEEP  (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
29
30 #define INT_DOWN        (0)
31 #define INT_UP          (1 << 8)
32
33 #define WAIT4INT        (S3C2410_ADCTSC_YM_SEN | \
34                          S3C2410_ADCTSC_YP_SEN | \
35                          S3C2410_ADCTSC_XP_SEN | \
36                          S3C2410_ADCTSC_XY_PST(3))
37
38 #define AUTOPST         (S3C2410_ADCTSC_YM_SEN | \
39                          S3C2410_ADCTSC_YP_SEN | \
40                          S3C2410_ADCTSC_XP_SEN | \
41                          S3C2410_ADCTSC_AUTO_PST | \
42                          S3C2410_ADCTSC_XY_PST(0))
43
44 #define FEAT_PEN_IRQ    (1 << 0)        /* HAS ADCCLRINTPNDNUP */
45
46 /* Per-touchscreen data. */
47
48 /**
49  * struct s3c2410ts - driver touchscreen state.
50  * @client: The ADC client we registered with the core driver.
51  * @dev: The device we are bound to.
52  * @input: The input device we registered with the input subsystem.
53  * @clock: The clock for the adc.
54  * @io: Pointer to the IO base.
55  * @xp: The accumulated X position data.
56  * @yp: The accumulated Y position data.
57  * @irq_tc: The interrupt number for pen up/down interrupt
58  * @count: The number of samples collected.
59  * @shift: The log2 of the maximum count to read in one go.
60  * @features: The features supported by the TSADC MOdule.
61  */
62 struct s3c2410ts {
63         struct s3c_adc_client *client;
64         struct device *dev;
65         struct input_dev *input;
66         struct clk *clock;
67         void __iomem *io;
68         unsigned long xp;
69         unsigned long yp;
70         int irq_tc;
71         int count;
72         int shift;
73         int features;
74 };
75
76 static struct s3c2410ts ts;
77
78 /**
79  * get_down - return the down state of the pen
80  * @data0: The data read from ADCDAT0 register.
81  * @data1: The data read from ADCDAT1 register.
82  *
83  * Return non-zero if both readings show that the pen is down.
84  */
85 static inline bool get_down(unsigned long data0, unsigned long data1)
86 {
87         /* returns true if both data values show stylus down */
88         return (!(data0 & S3C2410_ADCDAT0_UPDOWN) &&
89                 !(data1 & S3C2410_ADCDAT0_UPDOWN));
90 }
91
92 static void touch_timer_fire(struct timer_list *unused)
93 {
94         unsigned long data0;
95         unsigned long data1;
96         bool down;
97
98         data0 = readl(ts.io + S3C2410_ADCDAT0);
99         data1 = readl(ts.io + S3C2410_ADCDAT1);
100
101         down = get_down(data0, data1);
102
103         if (down) {
104                 if (ts.count == (1 << ts.shift)) {
105                         ts.xp >>= ts.shift;
106                         ts.yp >>= ts.shift;
107
108                         dev_dbg(ts.dev, "%s: X=%lu, Y=%lu, count=%d\n",
109                                 __func__, ts.xp, ts.yp, ts.count);
110
111                         input_report_abs(ts.input, ABS_X, ts.xp);
112                         input_report_abs(ts.input, ABS_Y, ts.yp);
113
114                         input_report_key(ts.input, BTN_TOUCH, 1);
115                         input_sync(ts.input);
116
117                         ts.xp = 0;
118                         ts.yp = 0;
119                         ts.count = 0;
120                 }
121
122                 s3c_adc_start(ts.client, 0, 1 << ts.shift);
123         } else {
124                 ts.xp = 0;
125                 ts.yp = 0;
126                 ts.count = 0;
127
128                 input_report_key(ts.input, BTN_TOUCH, 0);
129                 input_sync(ts.input);
130
131                 writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
132         }
133 }
134
135 static DEFINE_TIMER(touch_timer, touch_timer_fire);
136
137 /**
138  * stylus_irq - touchscreen stylus event interrupt
139  * @irq: The interrupt number
140  * @dev_id: The device ID.
141  *
142  * Called when the IRQ_TC is fired for a pen up or down event.
143  */
144 static irqreturn_t stylus_irq(int irq, void *dev_id)
145 {
146         unsigned long data0;
147         unsigned long data1;
148         bool down;
149
150         data0 = readl(ts.io + S3C2410_ADCDAT0);
151         data1 = readl(ts.io + S3C2410_ADCDAT1);
152
153         down = get_down(data0, data1);
154
155         /* TODO we should never get an interrupt with down set while
156          * the timer is running, but maybe we ought to verify that the
157          * timer isn't running anyways. */
158
159         if (down)
160                 s3c_adc_start(ts.client, 0, 1 << ts.shift);
161         else
162                 dev_dbg(ts.dev, "%s: count=%d\n", __func__, ts.count);
163
164         if (ts.features & FEAT_PEN_IRQ) {
165                 /* Clear pen down/up interrupt */
166                 writel(0x0, ts.io + S3C64XX_ADCCLRINTPNDNUP);
167         }
168
169         return IRQ_HANDLED;
170 }
171
172 /**
173  * s3c24xx_ts_conversion - ADC conversion callback
174  * @client: The client that was registered with the ADC core.
175  * @data0: The reading from ADCDAT0.
176  * @data1: The reading from ADCDAT1.
177  * @left: The number of samples left.
178  *
179  * Called when a conversion has finished.
180  */
181 static void s3c24xx_ts_conversion(struct s3c_adc_client *client,
182                                   unsigned data0, unsigned data1,
183                                   unsigned *left)
184 {
185         dev_dbg(ts.dev, "%s: %d,%d\n", __func__, data0, data1);
186
187         ts.xp += data0;
188         ts.yp += data1;
189
190         ts.count++;
191
192         /* From tests, it seems that it is unlikely to get a pen-up
193          * event during the conversion process which means we can
194          * ignore any pen-up events with less than the requisite
195          * count done.
196          *
197          * In several thousand conversions, no pen-ups where detected
198          * before count completed.
199          */
200 }
201
202 /**
203  * s3c24xx_ts_select - ADC selection callback.
204  * @client: The client that was registered with the ADC core.
205  * @select: The reason for select.
206  *
207  * Called when the ADC core selects (or deslects) us as a client.
208  */
209 static void s3c24xx_ts_select(struct s3c_adc_client *client, unsigned select)
210 {
211         if (select) {
212                 writel(S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST,
213                        ts.io + S3C2410_ADCTSC);
214         } else {
215                 mod_timer(&touch_timer, jiffies+1);
216                 writel(WAIT4INT | INT_UP, ts.io + S3C2410_ADCTSC);
217         }
218 }
219
220 /**
221  * s3c2410ts_probe - device core probe entry point
222  * @pdev: The device we are being bound to.
223  *
224  * Initialise, find and allocate any resources we need to run and then
225  * register with the ADC and input systems.
226  */
227 static int s3c2410ts_probe(struct platform_device *pdev)
228 {
229         struct s3c2410_ts_mach_info *info;
230         struct device *dev = &pdev->dev;
231         struct input_dev *input_dev;
232         struct resource *res;
233         int ret = -EINVAL;
234
235         /* Initialise input stuff */
236         memset(&ts, 0, sizeof(struct s3c2410ts));
237
238         ts.dev = dev;
239
240         info = dev_get_platdata(dev);
241         if (!info) {
242                 dev_err(dev, "no platform data, cannot attach\n");
243                 return -EINVAL;
244         }
245
246         dev_dbg(dev, "initialising touchscreen\n");
247
248         ts.clock = clk_get(dev, "adc");
249         if (IS_ERR(ts.clock)) {
250                 dev_err(dev, "cannot get adc clock source\n");
251                 return -ENOENT;
252         }
253
254         ret = clk_prepare_enable(ts.clock);
255         if (ret) {
256                 dev_err(dev, "Failed! to enabled clocks\n");
257                 goto err_clk_get;
258         }
259         dev_dbg(dev, "got and enabled clocks\n");
260
261         ts.irq_tc = ret = platform_get_irq(pdev, 0);
262         if (ret < 0) {
263                 dev_err(dev, "no resource for interrupt\n");
264                 goto err_clk;
265         }
266
267         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
268         if (!res) {
269                 dev_err(dev, "no resource for registers\n");
270                 ret = -ENOENT;
271                 goto err_clk;
272         }
273
274         ts.io = ioremap(res->start, resource_size(res));
275         if (ts.io == NULL) {
276                 dev_err(dev, "cannot map registers\n");
277                 ret = -ENOMEM;
278                 goto err_clk;
279         }
280
281         /* inititalise the gpio */
282         if (info->cfg_gpio)
283                 info->cfg_gpio(to_platform_device(ts.dev));
284
285         ts.client = s3c_adc_register(pdev, s3c24xx_ts_select,
286                                      s3c24xx_ts_conversion, 1);
287         if (IS_ERR(ts.client)) {
288                 dev_err(dev, "failed to register adc client\n");
289                 ret = PTR_ERR(ts.client);
290                 goto err_iomap;
291         }
292
293         /* Initialise registers */
294         if ((info->delay & 0xffff) > 0)
295                 writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
296
297         writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
298
299         input_dev = input_allocate_device();
300         if (!input_dev) {
301                 dev_err(dev, "Unable to allocate the input device !!\n");
302                 ret = -ENOMEM;
303                 goto err_iomap;
304         }
305
306         ts.input = input_dev;
307         ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
308         ts.input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
309         input_set_abs_params(ts.input, ABS_X, 0, 0x3FF, 0, 0);
310         input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);
311
312         ts.input->name = "S3C24XX TouchScreen";
313         ts.input->id.bustype = BUS_HOST;
314         ts.input->id.vendor = 0xDEAD;
315         ts.input->id.product = 0xBEEF;
316         ts.input->id.version = 0x0102;
317
318         ts.shift = info->oversampling_shift;
319         ts.features = platform_get_device_id(pdev)->driver_data;
320
321         ret = request_irq(ts.irq_tc, stylus_irq, 0,
322                           "s3c2410_ts_pen", ts.input);
323         if (ret) {
324                 dev_err(dev, "cannot get TC interrupt\n");
325                 goto err_inputdev;
326         }
327
328         dev_info(dev, "driver attached, registering input device\n");
329
330         /* All went ok, so register to the input system */
331         ret = input_register_device(ts.input);
332         if (ret < 0) {
333                 dev_err(dev, "failed to register input device\n");
334                 ret = -EIO;
335                 goto err_tcirq;
336         }
337
338         return 0;
339
340  err_tcirq:
341         free_irq(ts.irq_tc, ts.input);
342  err_inputdev:
343         input_free_device(ts.input);
344  err_iomap:
345         iounmap(ts.io);
346  err_clk:
347         clk_disable_unprepare(ts.clock);
348         del_timer_sync(&touch_timer);
349  err_clk_get:
350         clk_put(ts.clock);
351         return ret;
352 }
353
354 /**
355  * s3c2410ts_remove - device core removal entry point
356  * @pdev: The device we are being removed from.
357  *
358  * Free up our state ready to be removed.
359  */
360 static int s3c2410ts_remove(struct platform_device *pdev)
361 {
362         free_irq(ts.irq_tc, ts.input);
363         del_timer_sync(&touch_timer);
364
365         clk_disable_unprepare(ts.clock);
366         clk_put(ts.clock);
367
368         input_unregister_device(ts.input);
369         iounmap(ts.io);
370
371         return 0;
372 }
373
374 #ifdef CONFIG_PM
375 static int s3c2410ts_suspend(struct device *dev)
376 {
377         writel(TSC_SLEEP, ts.io + S3C2410_ADCTSC);
378         disable_irq(ts.irq_tc);
379         clk_disable(ts.clock);
380
381         return 0;
382 }
383
384 static int s3c2410ts_resume(struct device *dev)
385 {
386         struct platform_device *pdev = to_platform_device(dev);
387         struct s3c2410_ts_mach_info *info = dev_get_platdata(&pdev->dev);
388
389         clk_enable(ts.clock);
390         enable_irq(ts.irq_tc);
391
392         /* Initialise registers */
393         if ((info->delay & 0xffff) > 0)
394                 writel(info->delay & 0xffff, ts.io + S3C2410_ADCDLY);
395
396         writel(WAIT4INT | INT_DOWN, ts.io + S3C2410_ADCTSC);
397
398         return 0;
399 }
400
401 static const struct dev_pm_ops s3c_ts_pmops = {
402         .suspend        = s3c2410ts_suspend,
403         .resume         = s3c2410ts_resume,
404 };
405 #endif
406
407 static const struct platform_device_id s3cts_driver_ids[] = {
408         { "s3c2410-ts", 0 },
409         { "s3c2440-ts", 0 },
410         { "s3c64xx-ts", FEAT_PEN_IRQ },
411         { }
412 };
413 MODULE_DEVICE_TABLE(platform, s3cts_driver_ids);
414
415 static struct platform_driver s3c_ts_driver = {
416         .driver         = {
417                 .name   = "samsung-ts",
418 #ifdef CONFIG_PM
419                 .pm     = &s3c_ts_pmops,
420 #endif
421         },
422         .id_table       = s3cts_driver_ids,
423         .probe          = s3c2410ts_probe,
424         .remove         = s3c2410ts_remove,
425 };
426 module_platform_driver(s3c_ts_driver);
427
428 MODULE_AUTHOR("Arnaud Patard <arnaud.patard@rtp-net.org>, "
429               "Ben Dooks <ben@simtec.co.uk>, "
430               "Simtec Electronics <linux@simtec.co.uk>");
431 MODULE_DESCRIPTION("S3C24XX Touchscreen driver");
432 MODULE_LICENSE("GPL v2");