]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/touch/arm/aaed2000/v2_0/src/aaed2000_ts.c
Initial revision
[karo-tx-redboot.git] / packages / devs / touch / arm / aaed2000 / v2_0 / src / aaed2000_ts.c
1 //==========================================================================
2 //
3 //      aaed2000_ts.c
4 //
5 //      Touchscreen driver for the Agilent aaed2000
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 //
13 // eCos is free software; you can redistribute it and/or modify it under
14 // the terms of the GNU General Public License as published by the Free
15 // Software Foundation; either version 2 or (at your option) any later version.
16 //
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20 // for more details.
21 //
22 // You should have received a copy of the GNU General Public License along
23 // with eCos; if not, write to the Free Software Foundation, Inc.,
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25 //
26 // As a special exception, if other files instantiate templates or use macros
27 // or inline functions from this file, or you compile this file and link it
28 // with other works to produce a work based on this file, this file does not
29 // by itself cause the resulting work to be covered by the GNU General Public
30 // License. However the source code for this file must still be made available
31 // in accordance with section (3) of the GNU General Public License.
32 //
33 // This exception does not invalidate any other reasons why a work based on
34 // this file might be covered by the GNU General Public License.
35 //
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37 // at http://sources.redhat.com/ecos/ecos-license/
38 // -------------------------------------------
39 //####ECOSGPLCOPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):    gthomas
44 // Contributors: gthomas
45 // Date:         2002-03-05
46 // Purpose:      
47 // Description:  Touchscreen driver for Agilent AAED2000
48 //
49 //####DESCRIPTIONEND####
50 //
51 //==========================================================================
52
53
54 #include <pkgconf/devs_touch_aaed2000.h>
55
56 #include <cyg/kernel/kapi.h>
57 #include <cyg/hal/hal_io.h>
58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/drv_api.h>
60 #include <cyg/hal/hal_intr.h>
61 #include <cyg/hal/aaed2000.h>
62 #include <cyg/infra/cyg_type.h>
63 #include <cyg/infra/cyg_ass.h>
64 #include <cyg/infra/diag.h>
65
66 #include <cyg/fileio/fileio.h>  // For select() functionality
67 static cyg_selinfo      ts_select_info; 
68 static cyg_bool         ts_select_active;
69
70 #include <cyg/io/devtab.h>
71
72 /* ADS7846 flags */
73 #define ADS_START               (1 << 7)
74 #define ADS_MEASURE_Y           (0x01 << 4)
75 #define ADS_MEASURE_X           (0x05 << 4)
76 #define ADS_MODE_12_BIT         0
77 #define ADS_PD0                 0
78
79 // Misc constants
80 #define TS_INT (1<<0)
81 #define X_THRESHOLD 0x80
82 #define Y_THRESHOLD 0x80
83
84 // Functions in this module
85
86 static Cyg_ErrNo ts_read(cyg_io_handle_t handle, 
87                          void *buffer, 
88                          cyg_uint32 *len);
89 static cyg_bool  ts_select(cyg_io_handle_t handle, 
90                            cyg_uint32 which, 
91                            cyg_addrword_t info);
92 static Cyg_ErrNo ts_set_config(cyg_io_handle_t handle, 
93                                cyg_uint32 key, 
94                                const void *buffer, 
95                                cyg_uint32 *len);
96 static Cyg_ErrNo ts_get_config(cyg_io_handle_t handle, 
97                                cyg_uint32 key, 
98                                void *buffer, 
99                                cyg_uint32 *len);
100 static bool      ts_init(struct cyg_devtab_entry *tab);
101 static Cyg_ErrNo ts_lookup(struct cyg_devtab_entry **tab, 
102                            struct cyg_devtab_entry *st, 
103                            const char *name);
104
105 CHAR_DEVIO_TABLE(aaed2000_ts_handlers,
106                  NULL,                                   // Unsupported write() function
107                  ts_read,
108                  ts_select,
109                  ts_get_config,
110                  ts_set_config);
111
112 CHAR_DEVTAB_ENTRY(aaed2000_ts_device,
113                   CYGDAT_DEVS_TOUCH_AAED2000_NAME,
114                   NULL,                                   // Base device name
115                   &aaed2000_ts_handlers,
116                   ts_init,
117                   ts_lookup,
118                   NULL);                                  // Private data pointer
119
120 struct _event {
121     short button_state;
122     short xPos, yPos;
123     short _unused;
124 };
125 #define MAX_EVENTS CYGNUM_DEVS_TOUCH_AAED2000_EVENT_BUFFER_SIZE
126 static int   num_events;
127 static int   _event_put, _event_get;
128 static struct _event _events[MAX_EVENTS];
129
130 static bool _is_open = false;
131 #ifdef DEBUG_RAW_EVENTS
132 static unsigned char _ts_buf[512];
133 static int _ts_buf_ptr = 0;
134 #endif
135
136 #define STACK_SIZE CYGNUM_HAL_STACK_SIZE_TYPICAL
137 static char ts_scan_stack[STACK_SIZE];
138 static cyg_thread ts_scan_thread_data;
139 static cyg_handle_t ts_scan_thread_handle;
140 #define SCAN_FREQ 20 // Hz
141 //#define SCAN_FREQ 5 // Hz
142 #define SCAN_DELAY ((1000/SCAN_FREQ)/10)
143
144
145 typedef struct {
146     short min;
147     short max;
148     short span;
149 } bounds;
150
151 static bounds xBounds = {1024, 0, 1024};
152 static bounds yBounds = {1024, 0, 1024};
153
154 static Cyg_ErrNo 
155 ts_read(cyg_io_handle_t handle, 
156         void *buffer, 
157         cyg_uint32 *len)
158 {
159     struct _event *ev;
160     int tot = *len;
161     unsigned char *bp = (unsigned char *)buffer;
162
163     cyg_scheduler_lock();  // Prevent interaction with DSR code
164     while (tot >= sizeof(struct _event)) {
165         if (num_events > 0) {
166             ev = &_events[_event_get++];
167             if (_event_get == MAX_EVENTS) {
168                 _event_get = 0;
169             }
170             // Self calibrate
171             if (ev->xPos > xBounds.max) xBounds.max = ev->xPos;
172             if (ev->xPos < xBounds.min) xBounds.min = ev->xPos;
173             if (ev->yPos > yBounds.max) yBounds.max = ev->yPos;
174             if (ev->yPos < yBounds.min) yBounds.min = ev->yPos;
175             if ((xBounds.span = xBounds.max - xBounds.min) <= 1) {
176                 xBounds.span = 1;
177             }
178             if ((yBounds.span = yBounds.max - yBounds.min) <= 1) {
179                 yBounds.span = 1;
180             }
181             // Scale values - done here so these potentially lengthy
182             // operations take place outside of interrupt processing
183 #ifdef DEBUG
184             diag_printf("Raw[%d,%d], X[%d,%d,%d], Y[%d,%d,%d]",
185                         ev->xPos, ev->yPos,
186                         xBounds.max, xBounds.min, xBounds.span,
187                         yBounds.max, yBounds.min, yBounds.span);
188 #endif
189             ev->xPos = 640 - (((xBounds.max - ev->xPos) * 640) / xBounds.span);
190             ev->yPos = 480 - (((yBounds.max - ev->yPos) * 480) / yBounds.span);
191 #ifdef DEBUG
192             diag_printf(", Cooked[%d,%d]\n",
193                         ev->xPos, ev->yPos);
194 #endif
195             memcpy(bp, ev, sizeof(*ev));
196             bp += sizeof(*ev);
197             tot -= sizeof(*ev);
198             num_events--;
199         } else {
200             break;  // No more events
201         }
202     }
203     cyg_scheduler_unlock(); // Allow DSRs again
204     *len -= tot;
205     return ENOERR;
206 }
207
208 static cyg_bool  
209 ts_select(cyg_io_handle_t handle, 
210           cyg_uint32 which, 
211           cyg_addrword_t info)
212 {
213     if (which == CYG_FREAD) {
214         cyg_scheduler_lock();  // Prevent interaction with DSR code
215         if (num_events > 0) {
216             cyg_scheduler_unlock();  // Reallow interaction with DSR code
217             return true;
218         }        
219         if (!ts_select_active) {
220             ts_select_active = true;
221             cyg_selrecord(info, &ts_select_info);
222         }
223         cyg_scheduler_unlock();  // Reallow interaction with DSR code
224     }
225     return false;
226 }
227
228 static Cyg_ErrNo 
229 ts_set_config(cyg_io_handle_t handle, 
230               cyg_uint32 key, 
231               const void *buffer, 
232               cyg_uint32 *len)
233 {
234     return EINVAL;
235 }
236
237 static Cyg_ErrNo 
238 ts_get_config(cyg_io_handle_t handle, 
239               cyg_uint32 key, 
240               void *buffer, 
241               cyg_uint32 *len)
242 {
243     return EINVAL;
244 }
245
246 static bool      
247 ts_init(struct cyg_devtab_entry *tab)
248 {
249     cyg_uint32 _dummy;
250
251     // Initialize SSP interface
252 #if 0
253     while (*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) {
254         _dummy = *(volatile cyg_uint32 *)AAEC_SSP_DR;  // Drain FIFO
255     }
256 #endif
257     *(volatile cyg_uint32 *)AAEC_SSP_CR0 = 
258         (1 << AAEC_SSP_CR0_SSE) |                    // SSP enable
259         (37 << AAEC_SSP_CR0_SCR) |                   // Serial clock rate
260         (AAEC_SSP_CR0_FRF_NAT << AAEC_SSP_CR0_FRF) | // MicroWire
261         ((12-1) << AAEC_SSP_CR0_SIZE);               // 12 bit words
262     *(volatile cyg_uint32 *)AAEC_SSP_CR1 =
263         (1 << AAEC_SSP_CR1_FEN);                     // Enable FIFO
264     *(volatile cyg_uint32 *)AAEC_SSP_CPSR = 2;       // Clock prescale
265     *(volatile cyg_uint32 *)AAEC_PFDDR &= ~(1<<0);  // TS uses port F bit 0
266     cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_TS);
267     cyg_selinit(&ts_select_info);
268     return true;
269 }
270
271 static cyg_uint32
272 read_ts(int axis)
273 {
274     cyg_uint32 res;
275
276     *(volatile cyg_uint32 *)AAEC_SSP_DR = (axis | ADS_START | ADS_MODE_12_BIT | ADS_PD0);
277     *(volatile cyg_uint32 *)AAEC_SSP_DR = (axis | ADS_START | ADS_MODE_12_BIT);
278     // Wait for data
279     while ((*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) == 0); 
280     res = *(volatile cyg_uint32 *)AAEC_SSP_DR;  // ignore first datum
281     // Wait for data
282     while ((*(volatile cyg_uint32 *)AAEC_SSP_SR & AAEC_SSP_SR_RNE) == 0); 
283     res = *(volatile cyg_uint32 *)AAEC_SSP_DR;
284     return res;
285 }
286
287 static void
288 ts_scan(cyg_addrword_t param)
289 {
290     short lastX, lastY;
291     short x, y;
292     struct _event *ev;
293     bool pen_down;
294
295     diag_printf("Touch Screen thread started\n");
296     // Discard the first sample - it's always 0
297     x = read_ts(ADS_MEASURE_X);
298     y = read_ts(ADS_MEASURE_Y);
299     lastX = lastY = -1;
300     pen_down = false;
301     while (true) {
302         cyg_thread_delay(SCAN_DELAY);
303         if ((*(volatile cyg_uint32 *)AAEC_PFDR & TS_INT) == 0) {
304             // Pen is down
305             x = read_ts(ADS_MEASURE_X);
306             y = read_ts(ADS_MEASURE_Y);
307 //            diag_printf("X = %x, Y = %x\n", x, y);
308             if ((x < X_THRESHOLD) || (y < Y_THRESHOLD)) {
309                 // Ignore 'bad' samples
310                 continue;
311             }
312             lastX = x;  lastY = y;
313             pen_down = true;
314         } else {
315             if (pen_down) {
316                 // Capture first 'up' event
317                 pen_down = false;
318                 x = lastX;
319                 y = lastY;
320             } else {
321                 continue;  // Nothing new to report
322             }
323         }
324         if (num_events < MAX_EVENTS) {
325             num_events++;
326             ev = &_events[_event_put++];
327             if (_event_put == MAX_EVENTS) {
328                 _event_put = 0;
329             }
330             ev->button_state = pen_down ? 0x04 : 0x00;
331             ev->xPos = x;
332             ev->yPos = y;
333             if (ts_select_active) {
334                 ts_select_active = false;
335                 cyg_selwakeup(&ts_select_info);
336             }
337         }
338 #ifdef DEBUG_RAW_EVENTS
339         memcpy(&_ts_buf[_ts_buf_ptr], pkt->data, 8);
340         _ts_buf_ptr += 8;
341         if (_ts_buf_ptr == 512) {
342             diag_printf("TS handler\n");
343             diag_dump_buf(_ts_buf, 512);
344             _ts_buf_ptr = 0;
345         }
346 #endif
347     }
348 }
349
350 static Cyg_ErrNo 
351 ts_lookup(struct cyg_devtab_entry **tab, 
352           struct cyg_devtab_entry *st, 
353           const char *name)
354 {
355     if (!_is_open) {
356         _is_open = true;
357         cyg_thread_create(1,                      // Priority
358                           ts_scan,                // entry
359                           0,                      // entry parameter
360                           "Touch Screen scan",    // Name
361                           &ts_scan_stack[0],      // Stack
362                           STACK_SIZE,             // Size
363                           &ts_scan_thread_handle, // Handle
364                           &ts_scan_thread_data    // Thread data structure
365         );
366         cyg_thread_resume(ts_scan_thread_handle);    // Start it
367     }
368     return ENOERR;
369 }