]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/edb7xxx/v2_0/misc/lcd_panel_support.c
Initial revision
[karo-tx-redboot.git] / packages / hal / arm / edb7xxx / v2_0 / misc / lcd_panel_support.c
1 //==========================================================================
2 //
3 //        panel_support.c
4 //
5 //        Cirrus Logic EDB7xxx eval board LCD touch panel support code
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:          1999-09-13
46 // Description:   Tool used to support the LCD touch panel
47 //####DESCRIPTIONEND####
48
49 static char lcd_panel_server_stack[STACK_SIZE];
50 static cyg_thread lcd_panel_server_thread_data;
51 static cyg_handle_t lcd_panel_server_thread_handle;
52
53 static cyg_interrupt lcd_panel_interrupt;
54 static cyg_handle_t  lcd_panel_interrupt_handle;
55
56 static cyg_mbox      lcd_panel_events_mbox;
57 static cyg_handle_t  lcd_panel_events_mbox_handle;
58 static cyg_sem_t     lcd_panel_sem;
59
60 #define SYNCIO_TXFRMEN     (1<<14)
61 #define SYNCIO_FRAMELEN(n) (n<<8)
62 #define ADC_START          (1<<7)
63 #define ADC_CHAN(n)        (n<<4)
64 #define ADC_UNIPOLAR       (1<<3)
65 #define ADC_SINGLE         (1<<2)
66 #define ADC_EXT_CLOCK      (3<<0)
67 #define TOUCH_CTL          KBD_PORT
68
69 // FUNCTIONS
70
71 static cyg_uint32
72 adc_sample(int chan)
73 {
74     cyg_uint32 val;
75     *(volatile cyg_uint32 *)SYNCIO = SYNCIO_TXFRMEN | SYNCIO_FRAMELEN(24) |
76         ADC_START | ADC_CHAN(chan) | ADC_UNIPOLAR | ADC_SINGLE | ADC_EXT_CLOCK;
77     while (*(volatile cyg_uint32 *)SYSFLG1 & SYSFLG1_SSIBUSY) ;
78     val = *(volatile cyg_uint32 *)SYNCIO;
79     return (val & 0xFFFF);
80 }
81
82 static void
83 panel_delay(void)
84 {
85     volatile int i;
86     for (i = 0;  i < 800;  i++) ;
87 }
88
89 // This ISR is called when the touch panel interrupt occurs
90 static int 
91 lcd_panel_isr(cyg_vector_t vector, cyg_addrword_t data, HAL_SavedRegisters *regs)
92 {
93     cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_EINT2);
94     return (CYG_ISR_HANDLED|CYG_ISR_CALL_DSR);  // Run the DSR
95 }
96
97 // This DSR starts up the touch panel [logical] processing
98 static void
99 lcd_panel_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
100 {
101     // Tell the panel processing thread to give it a shot
102     cyg_semaphore_post(&lcd_panel_sem);
103 }
104
105 // Assumption: if the keypress vanishes for 5*20 ms, it probably isn't there
106 #define LCD_PANEL_TIMEOUT 5
107
108 static __inline__ int
109 abs(int x)
110 {
111     if (x < 0) return -x;
112     return x;
113 }
114
115 static void
116 lcd_panel_server(cyg_addrword_t p)
117 {
118     int iX, iY, newX, newY, diffX, diffY, timeout, samples;
119     cyg_uint32 event;
120     diag_printf("LCD panel server here\n");
121     while (TRUE) {
122         cyg_semaphore_wait(&lcd_panel_sem);
123         samples = 0;  iX = 0;  iY = 0;
124         // Wait for press to go away (no drag support)
125         timeout = 0;
126         while (timeout < LCD_PANEL_TIMEOUT) {
127             *(volatile cyg_uint8 *)TOUCH_CTL = 0x00;  // Disable drives
128             while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ;
129             *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  // Idle state (so interrupt works)
130             cyg_thread_delay(2);  // Wait 20 ms
131             if (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) {
132                 // Still pressed
133                 // Drive TSPY, ground TSMY, and disconnect TSPX and TSMX
134                 *(volatile cyg_uint8 *)TOUCH_CTL = 0x50;  
135                 panel_delay();
136                 newY = adc_sample(2);
137                 // Drive TSPX, ground TSMX, and disconnect TSPY and TSMY
138                 *(volatile cyg_uint8 *)TOUCH_CTL = 0xA0;  
139                 panel_delay();
140                 newX = adc_sample(7);
141 #if 0
142                 diag_printf("timeout: %d, ISR: %x, newX: %d, newY: %d\n", 
143                             timeout, *(volatile cyg_uint32 *)INTSR1, newX, newY);
144 #endif
145                 // See if this sample makes any sense
146                 if (samples) {
147                     diffX = abs(iX/samples - newX);
148                     diffY = abs(iY/samples - newY);
149                     if ((diffX <= ((iX/samples)/4)) &&
150                         (diffY <= ((iY/samples)/4))) {
151                         samples++;
152                         iX += newX;
153                         iY += newY;
154                     } else {
155 #if 0
156                         diag_printf("Discard - newX: %d, X: %d, newY: %d, Y: %d\n",
157                                     newX, iX/samples, newY, iY/samples);
158 #endif
159                         break;
160                     }
161                 } else {
162                     iX = newX;
163                     iY = newY;
164                     samples = 1;
165                 }
166                 timeout = 0;
167             } else {
168                 timeout++;
169             }
170         }
171         if (samples) {
172             // Send event to user level
173             event = (iX/samples)<<16 | (iY/samples);
174             if (!cyg_mbox_tryput(lcd_panel_events_mbox_handle, (void *)event)) {
175                 diag_printf("LCD event lost: %x\n", event);
176             }
177         }
178         *(volatile cyg_uint8 *)TOUCH_CTL = 0x00;  // Disable drives
179         while (*(volatile cyg_uint32 *)INTSR1 & INTSR1_EINT2) ;
180         *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  // Idle state (so interrupt works)
181         cyg_thread_delay(10);
182         cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
183     }
184 }
185
186 static void
187 lcd_panel_init(void)
188 {
189     // Enable touch panel
190     *(volatile cyg_uint8 *)PEDR   |= 0x04;  
191
192     // Idle state (so interrupt works)
193     *(volatile cyg_uint8 *)TOUCH_CTL = 0x70;  
194
195     // Enable ADC machinery
196     *(volatile cyg_uint32 *)SYSCON1 |= SYSCON1_ADC_CLOCK_128kHZ;
197
198     cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EINT2,
199                              99,                     // Priority - what goes here?
200                              0,                      //  Data item passed to interrupt handler
201                              lcd_panel_isr,
202                              lcd_panel_dsr,
203                              &lcd_panel_interrupt_handle,
204                              &lcd_panel_interrupt);
205     cyg_drv_interrupt_attach(lcd_panel_interrupt_handle);
206     cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EINT2);
207     cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EINT2);
208     // Set up the mbox for panel data
209     cyg_mbox_create(&lcd_panel_events_mbox_handle, &lcd_panel_events_mbox);
210     // This semaphore is set when there is a touch
211     cyg_semaphore_init(&lcd_panel_sem, 0);  
212     // Create a thread whose job it is to de-bounce the keyboard and
213     // actually process the input, turning it into a series of events
214     cyg_thread_create(10,                           // Priority - just a number
215                       lcd_panel_server,             // entry
216                       0,                            // initial parameter
217                       "LCD_PANEL_server",           // Name
218                       &lcd_panel_server_stack[0],   // Stack
219                       STACK_SIZE,                   // Size
220                       &lcd_panel_server_thread_handle,    // Handle
221                       &lcd_panel_server_thread_data       // Thread data structure
222             );
223     cyg_thread_resume(lcd_panel_server_thread_handle);  // Start it
224 }