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