1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2010-01-01     Yi.Qiu      first version
9  */
10 
11 #include <rthw.h>
12 #include <rtthread.h>
13 #include <s3c24x0.h>
14 
15 #ifdef PKG_USING_GUIENGINE
16 #include <rtgui/rtgui_system.h>
17 #include <rtgui/rtgui_server.h>
18 #include <rtgui/event.h>
19 #endif
20 
21 #define TOUCH_SWAP_XY
22 
23 #include "touch.h"
24 
25 /* ADCCON Register Bits */
26 #define S3C2410_ADCCON_ECFLG            (1<<15)
27 #define S3C2410_ADCCON_PRSCEN           (1<<14)
28 #define S3C2410_ADCCON_PRSCVL(x)        (((x)&0xFF)<<6)
29 #define S3C2410_ADCCON_PRSCVLMASK       (0xFF<<6)
30 #define S3C2410_ADCCON_SELMUX(x)        (((x)&0x7)<<3)
31 #define S3C2410_ADCCON_MUXMASK          (0x7<<3)
32 #define S3C2410_ADCCON_STDBM            (1<<2)
33 #define S3C2410_ADCCON_READ_START       (1<<1)
34 #define S3C2410_ADCCON_ENABLE_START     (1<<0)
35 #define S3C2410_ADCCON_STARTMASK        (0x3<<0)
36 
37 /* ADCTSC Register Bits */
38 #define S3C2410_ADCTSC_UD_SEN           (1<<8) /* ghcstop add for s3c2440a */
39 #define S3C2410_ADCTSC_YM_SEN           (1<<7)
40 #define S3C2410_ADCTSC_YP_SEN           (1<<6)
41 #define S3C2410_ADCTSC_XM_SEN           (1<<5)
42 #define S3C2410_ADCTSC_XP_SEN           (1<<4)
43 #define S3C2410_ADCTSC_PULL_UP_DISABLE  (1<<3)
44 #define S3C2410_ADCTSC_AUTO_PST         (1<<2)
45 #define S3C2410_ADCTSC_XY_PST(x)        (((x)&0x3)<<0)
46 
47 /* ADCDAT0 Bits */
48 #define S3C2410_ADCDAT0_UPDOWN          (1<<15)
49 #define S3C2410_ADCDAT0_AUTO_PST        (1<<14)
50 #define S3C2410_ADCDAT0_XY_PST          (0x3<<12)
51 #define S3C2410_ADCDAT0_XPDATA_MASK     (0x03FF)
52 
53 /* ADCDAT1 Bits */
54 #define S3C2410_ADCDAT1_UPDOWN          (1<<15)
55 #define S3C2410_ADCDAT1_AUTO_PST        (1<<14)
56 #define S3C2410_ADCDAT1_XY_PST          (0x3<<12)
57 #define S3C2410_ADCDAT1_YPDATA_MASK     (0x03FF)
58 
59 #define WAIT4INT(x)  (((x)<<8) | \
60              S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
61              S3C2410_ADCTSC_XY_PST(3))
62 
63 #define AUTOPST      (S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
64              S3C2410_ADCTSC_AUTO_PST | S3C2410_ADCTSC_XY_PST(0))
65 
66 #define X_MIN       74
67 #define X_MAX       934
68 #define Y_MIN       920
69 #define Y_MAX       89
70 
71 struct s3c2410ts
72 {
73     long xp;
74     long yp;
75     int count;
76     int shift;
77 
78     int delay;
79     int presc;
80 
81     char phys[32];
82 };
83 static struct s3c2410ts ts;
84 
85 struct rtgui_touch_device
86 {
87     struct rt_device parent;
88 
89     rt_timer_t poll_timer;
90     rt_uint16_t x, y;
91 
92     rt_bool_t calibrating;
93     rt_touch_calibration_func_t calibration_func;
94 
95     rt_touch_eventpost_func_t eventpost_func;
96     void *eventpost_param;
97 
98     rt_uint16_t min_x, max_x;
99     rt_uint16_t min_y, max_y;
100 
101     rt_uint16_t width;
102     rt_uint16_t height;
103 
104     rt_bool_t first_down_report;
105 };
106 static struct rtgui_touch_device *touch = RT_NULL;
107 
108 #ifdef PKG_USING_GUIENGINE
report_touch_input(int updown)109 static void report_touch_input(int updown)
110 {
111     struct rtgui_event_mouse emouse;
112 
113     RTGUI_EVENT_MOUSE_BUTTON_INIT(&emouse);
114     emouse.wid = RT_NULL;
115 
116     /* set emouse button */
117     emouse.button = RTGUI_MOUSE_BUTTON_LEFT;
118     emouse.parent.sender = RT_NULL;
119 
120     if (updown)
121     {
122         ts.xp = ts.xp / ts.count;
123         ts.yp = ts.yp / ts.count;;
124 
125     #ifdef TOUCH_SWAP_XY
126         ts.xp = ts.xp + ts.yp;
127         ts.yp = ts.xp - ts.yp;
128         ts.xp = ts.xp - ts.yp;
129     #endif
130 
131         if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
132         {
133             touch->x = ts.xp;
134             touch->y = ts.yp;
135         }
136         else
137         {
138             if (touch->max_x > touch->min_x)
139             {
140                 touch->x = touch->width * (ts.xp-touch->min_x)/(touch->max_x-touch->min_x);
141             }
142             else
143             {
144                 touch->x = touch->width * ( touch->min_x - ts.xp ) / (touch->min_x-touch->max_x);
145             }
146 
147             if (touch->max_y > touch->min_y)
148             {
149                 touch->y = touch->height * ( ts.yp - touch->min_y ) / (touch->max_y-touch->min_y);
150             }
151             else
152             {
153                 touch->y = touch->height * ( touch->min_y - ts.yp ) / (touch->min_y-touch->max_y);
154             }
155         }
156 
157         emouse.x = touch->x;
158         emouse.y = touch->y;
159         if (touch->first_down_report == RT_TRUE)
160         {
161             emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
162             emouse.button |= RTGUI_MOUSE_BUTTON_DOWN;
163         }
164         else
165         {
166             emouse.parent.type = RTGUI_EVENT_MOUSE_MOTION;
167             emouse.button = 0;
168         }
169     }
170     else
171     {
172         emouse.x = touch->x;
173         emouse.y = touch->y;
174         emouse.parent.type = RTGUI_EVENT_MOUSE_BUTTON;
175         emouse.button |= RTGUI_MOUSE_BUTTON_UP;
176         if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
177         {
178             /* callback function */
179             touch->calibration_func(emouse.x, emouse.y);
180         }
181     }
182 
183     /* rt_kprintf("touch %s: ts.x: %d, ts.y: %d\n", updown? "down" : "up",
184     touch->x, touch->y); */
185 
186     /* send event to server */
187     if (touch->calibrating != RT_TRUE)
188     {
189         rtgui_server_post_event((&emouse.parent), sizeof(emouse));
190     }
191 }
192 #else
report_touch_input(int updown)193 static void report_touch_input(int updown)
194 {
195     struct rt_touch_event touch_event;
196 
197     if (updown)
198     {
199         ts.xp = ts.xp / ts.count;
200         ts.yp = ts.yp / ts.count;
201 
202         if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
203         {
204             touch->x = ts.xp;
205             touch->y = ts.yp;
206         }
207         else
208         {
209             if (touch->max_x > touch->min_x)
210             {
211                 touch->x = touch->width * ( ts.xp - touch->min_x ) / (touch->max_x-touch->min_x);
212             }
213             else
214             {
215                 touch->x = touch->width * ( touch->min_x - ts.xp ) / (touch->min_x-touch->max_x);
216             }
217 
218             if (touch->max_y > touch->min_y)
219             {
220                 touch->y = touch->height * ( ts.yp - touch->min_y ) / (touch->max_y-touch->min_y);
221             }
222             else
223             {
224                 touch->y = touch->height * ( touch->min_y - ts.yp ) / (touch->min_y-touch->max_y);
225             }
226         }
227 
228         touch_event.x = touch->x;
229         touch_event.y = touch->y;
230         touch_event.pressed = 1;
231 
232         if (touch->first_down_report == RT_TRUE)
233         {
234             if (touch->calibrating != RT_TRUE && touch->eventpost_func)
235             {
236                 touch->eventpost_func(touch->eventpost_param, &touch_event);
237             }
238         }
239     }
240     else
241     {
242         touch_event.x = touch->x;
243         touch_event.y = touch->y;
244         touch_event.pressed = 0;
245 
246         if ((touch->calibrating == RT_TRUE) && (touch->calibration_func != RT_NULL))
247         {
248             /* callback function */
249             touch->calibration_func(touch_event.x, touch_event.y);
250         }
251 
252         if (touch->calibrating != RT_TRUE && touch->eventpost_func)
253         {
254             touch->eventpost_func(touch->eventpost_param, &touch_event);
255         }
256     }
257 }
258 #endif
259 
touch_timer_fire(void * parameter)260 static void touch_timer_fire(void *parameter)
261 {
262     rt_uint32_t data0;
263     rt_uint32_t data1;
264     int updown;
265 
266     data0 = ADCDAT0;
267     data1 = ADCDAT1;
268 
269     updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
270 
271     if (updown)
272     {
273         if (ts.count != 0)
274         {
275             report_touch_input(updown);
276         }
277 
278         ts.xp = 0;
279         ts.yp = 0;
280         ts.count = 0;
281 
282         ADCTSC = S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST;
283         ADCCON |= S3C2410_ADCCON_ENABLE_START;
284     }
285 }
286 
s3c2410_adc_stylus_action(void)287 static void s3c2410_adc_stylus_action(void)
288 {
289     rt_uint32_t data0;
290     rt_uint32_t data1;
291 
292     data0 = ADCDAT0;
293     data1 = ADCDAT1;
294 
295     ts.xp += data0 & S3C2410_ADCDAT0_XPDATA_MASK;
296     ts.yp += data1 & S3C2410_ADCDAT1_YPDATA_MASK;
297     ts.count ++;
298 
299     if (ts.count < (1<<ts.shift))
300     {
301         ADCTSC = S3C2410_ADCTSC_PULL_UP_DISABLE | AUTOPST;
302         ADCCON |= S3C2410_ADCCON_ENABLE_START;
303     }
304     else
305     {
306         if (touch->first_down_report)
307         {
308             report_touch_input(1);
309             ts.xp = 0;
310             ts.yp = 0;
311             ts.count = 0;
312             touch->first_down_report = 0;
313         }
314         /* start timer */
315         rt_timer_start(touch->poll_timer);
316         ADCTSC = WAIT4INT(1);
317     }
318 
319     SUBSRCPND |= BIT_SUB_ADC;
320 }
321 
s3c2410_intc_stylus_updown(void)322 static void s3c2410_intc_stylus_updown(void)
323 {
324     rt_uint32_t data0;
325     rt_uint32_t data1;
326     int updown;
327 
328     data0 = ADCDAT0;
329     data1 = ADCDAT1;
330 
331     updown = (!(data0 & S3C2410_ADCDAT0_UPDOWN)) && (!(data1 & S3C2410_ADCDAT0_UPDOWN));
332 
333     /* rt_kprintf("stylus: %s\n", updown? "down" : "up"); */
334 
335     if (updown)
336     {
337         touch_timer_fire(0);
338     }
339     else
340     {
341         /* stop timer */
342         rt_timer_stop(touch->poll_timer);
343         touch->first_down_report = RT_TRUE;
344         if (ts.xp >= 0 && ts.yp >= 0)
345         {
346             report_touch_input(updown);
347         }
348         ts.count = 0;
349         ADCTSC = WAIT4INT(0);
350     }
351 
352     SUBSRCPND |= BIT_SUB_TC;
353 }
354 
rt_touch_handler(int irqno,void * param)355 static void rt_touch_handler(int irqno, void *param)
356 {
357     if (SUBSRCPND & BIT_SUB_ADC)
358     {
359         /* INT_SUB_ADC */
360         s3c2410_adc_stylus_action();
361     }
362 
363     if (SUBSRCPND & BIT_SUB_TC)
364     {
365         /* INT_SUB_TC */
366         s3c2410_intc_stylus_updown();
367     }
368 
369     /* clear interrupt */
370     INTPND |= (1ul << INTADC);
371 }
372 
373 /* RT-Thread Device Interface */
rtgui_touch_init(rt_device_t dev)374 static rt_err_t rtgui_touch_init(rt_device_t dev)
375 {
376     /* init touch screen structure */
377     rt_memset(&ts, 0, sizeof(struct s3c2410ts));
378 
379     ts.delay = 50000;
380     ts.presc = 9;
381     ts.shift = 2;
382     ts.count = 0;
383     ts.xp = ts.yp = 0;
384 
385     ADCCON = S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(ts.presc);
386     ADCDLY = ts.delay;
387 
388     ADCTSC = WAIT4INT(0);
389 
390     rt_hw_interrupt_install(INTADC, rt_touch_handler, RT_NULL , "INTADC");
391     rt_hw_interrupt_umask(INTADC);
392 
393     /* clear interrupt */
394     INTPND |= (1ul << INTADC);
395 
396     SUBSRCPND |= BIT_SUB_TC;
397     SUBSRCPND |= BIT_SUB_ADC;
398 
399     /* install interrupt handler */
400     INTSUBMSK &= ~BIT_SUB_ADC;
401     INTSUBMSK &= ~BIT_SUB_TC;
402 
403     touch->first_down_report = RT_TRUE;
404 
405     return RT_EOK;
406 }
407 
rtgui_touch_control(rt_device_t dev,int cmd,void * args)408 static rt_err_t rtgui_touch_control(rt_device_t dev, int cmd, void *args)
409 {
410     switch (cmd)
411     {
412     case RT_TOUCH_CALIBRATION:
413         touch->calibrating = RT_TRUE;
414         touch->calibration_func = (rt_touch_calibration_func_t)args;
415         break;
416 
417     case RT_TOUCH_NORMAL:
418         touch->calibrating = RT_FALSE;
419         break;
420 
421     case RT_TOUCH_CALIBRATION_DATA:
422     {
423         struct calibration_data *data;
424 
425         data = (struct calibration_data *)args;
426 
427         /* update */
428         touch->min_x = data->min_x;
429         touch->max_x = data->max_x;
430         touch->min_y = data->min_y;
431         touch->max_y = data->max_y;
432 
433         /*
434             rt_kprintf("min_x = %d, max_x = %d, min_y = %d, max_y = %d\n",
435                 touch->min_x, touch->max_x, touch->min_y, touch->max_y);
436         */
437     }
438         break;
439 
440     case RT_TOUCH_EVENTPOST:
441         touch->eventpost_func = (rt_touch_eventpost_func_t)args;
442         break;
443 
444     case RT_TOUCH_EVENTPOST_PARAM:
445         touch->eventpost_param = args;
446         break;
447     }
448 
449     return RT_EOK;
450 }
451 
rtgui_touch_hw_init(void)452 int rtgui_touch_hw_init(void)
453 {
454     rt_err_t result = RT_FALSE;
455     rt_device_t device = RT_NULL;
456     struct rt_device_graphic_info info;
457 
458     touch = (struct rtgui_touch_device *)rt_malloc(sizeof(struct rtgui_touch_device));
459     if (touch == RT_NULL)
460         return -RT_ERROR; /* no memory yet */
461 
462     /* clear device structure */
463     rt_memset(&(touch->parent), 0, sizeof(struct rt_device));
464     touch->calibrating = RT_FALSE;
465     touch->min_x = X_MIN;
466     touch->max_x = X_MAX;
467     touch->min_y = Y_MIN;
468     touch->max_y = Y_MAX;
469     touch->eventpost_func  = RT_NULL;
470     touch->eventpost_param = RT_NULL;
471 
472     /* init device structure */
473     touch->parent.type = RT_Device_Class_Unknown;
474     touch->parent.init = rtgui_touch_init;
475     touch->parent.control = rtgui_touch_control;
476     touch->parent.user_data = RT_NULL;
477 
478     device = rt_device_find("lcd");
479     if (device == RT_NULL)
480     {
481         rt_kprintf("No lcd found\n");
482         return -RT_ERROR; /* no this device */
483     }
484 
485     /* get graphic device info */
486     result = rt_device_control(device, RTGRAPHIC_CTRL_GET_INFO, &info);
487     if (result != RT_EOK)
488     {
489         /* get device information failed */
490         rt_kprintf("Get graphic device info failed\n");
491         return -RT_ERROR;
492     }
493 
494     touch->width = info.width;
495     touch->height = info.height;
496 
497     /* create 1/8 second timer */
498     touch->poll_timer = rt_timer_create("touch", touch_timer_fire, RT_NULL,
499                                         RT_TICK_PER_SECOND/8, RT_TIMER_FLAG_PERIODIC);
500 
501     /* register touch device to RT-Thread */
502     rt_device_register(&(touch->parent), "touch", RT_DEVICE_FLAG_RDWR);
503 
504     return RT_EOK;
505 }
506 
507 INIT_PREV_EXPORT(rtgui_touch_hw_init);
508