]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/hal/arm/lpc2xxx/var/v2_0/src/lpc2xxx_misc.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / hal / arm / lpc2xxx / var / v2_0 / src / lpc2xxx_misc.c
1 /*==========================================================================
2 //
3 //      lpc2xxx_misc.c
4 //
5 //      HAL misc variant support code for Philips LPC2xxx
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 // Copyright (C) 2003 Nick Garnett <nickg@calivar.com>
13 // Copyright (C) 2004 eCosCentric Limited 
14 //
15 // eCos is free software; you can redistribute it and/or modify it under
16 // the terms of the GNU General Public License as published by the Free
17 // Software Foundation; either version 2 or (at your option) any later version.
18 //
19 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
20 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
22 // for more details.
23 //
24 // You should have received a copy of the GNU General Public License along
25 // with eCos; if not, write to the Free Software Foundation, Inc.,
26 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 //
28 // As a special exception, if other files instantiate templates or use macros
29 // or inline functions from this file, or you compile this file and link it
30 // with other works to produce a work based on this file, this file does not
31 // by itself cause the resulting work to be covered by the GNU General Public
32 // License. However the source code for this file must still be made available
33 // in accordance with section (3) of the GNU General Public License.
34 //
35 // This exception does not invalidate any other reasons why a work based on
36 // this file might be covered by the GNU General Public License.
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //==========================================================================
40 //#####DESCRIPTIONBEGIN####
41 //
42 // Author(s):    jani 
43 // Contributors: gthomas, jskov, nickg, tkoeller
44 // Date:         2001-07-12
45 // Purpose:      HAL board support
46 // Description:  Implementations of HAL board interfaces
47 //
48 //####DESCRIPTIONEND####
49 //
50 //========================================================================*/
51
52 #include <pkgconf/hal.h>
53 #include <pkgconf/hal_arm_lpc2xxx.h>
54
55 #include <cyg/infra/cyg_type.h>         // base types
56 #include <cyg/infra/cyg_trac.h>         // tracing macros
57 #include <cyg/infra/cyg_ass.h>          // assertion macros
58
59 #include <cyg/hal/hal_io.h>             // IO macros
60 #include <cyg/hal/hal_arch.h>           // Register state info
61 #include <cyg/hal/hal_diag.h>
62 #include <cyg/hal/hal_intr.h>           // necessary?
63 #include <cyg/hal/hal_cache.h>
64 #include <cyg/hal/hal_if.h>             // calling interface
65 #include <cyg/hal/hal_misc.h>           // helper functions
66 #ifdef CYGDBG_HAL_DEBUG_GDB_BREAK_SUPPORT
67 #include <cyg/hal/drv_api.h>            // HAL ISR support
68 #endif
69 #include <cyg/hal/var_io.h>             // platform registers
70
71 #include <cyg/infra/diag.h>     // For diagnostic printing
72
73
74 // -------------------------------------------------------------------------
75 // eCos clock support
76 // Use TIMER0
77 static cyg_uint32 _period;
78
79 void hal_clock_initialize(cyg_uint32 period)
80 {
81     CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER0_BASE;
82
83     period = period / (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / CYGNUM_HAL_ARM_LPC2XXX_PCLK);
84
85     // Disable and reset counter
86     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 2);
87     
88     // set prescale register to 0
89     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxPR, 0);
90
91     // Set up match register 
92     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMR0, period);
93     
94     // Reset and generate interrupt on match
95     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMCR, 
96                      CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_INT | 
97                      CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_RESET);
98
99     // Enable counter
100     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 1);
101 }
102
103 void hal_clock_reset(cyg_uint32 vector, cyg_uint32 period)
104 {
105     CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER0_BASE;
106
107     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxIR, 
108                      CYGARC_HAL_LPC2XXX_REG_TxIR_MR0);  // Clear interrupt
109
110     if (period != _period) {
111         hal_clock_initialize(period);
112     }
113     _period = period;
114
115 }
116
117 void hal_clock_read(cyg_uint32 *pvalue)
118 {
119     CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER0_BASE;
120     cyg_uint32 val;
121
122     HAL_READ_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTC, val);
123     *pvalue = val;
124 }
125
126 // -------------------------------------------------------------------------
127 //
128 // Delay for some number of micro-seconds
129 // use TIMER1
130 //
131 void hal_delay_us(cyg_int32 usecs)
132 {
133     CYG_ADDRESS timer = CYGARC_HAL_LPC2XXX_REG_TIMER1_BASE;
134     cyg_uint32 stat;
135     cyg_uint64 ticks;
136
137     // Calculate how many timer ticks the required number of
138     // microseconds equate to. We do this calculation in 64 bit
139     // arithmetic to avoid overflow.
140     ticks = CYGNUM_HAL_ARM_LPC2XXX_PCLK;
141     ticks = (((cyg_uint64)usecs) * (ticks))/1000000LL;
142     
143     // Disable and reset counter
144     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 2);
145     
146     // Stop on match
147     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMR0, ticks);
148     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxMCR, 
149                      CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_STOP | 
150                      CYGARC_HAL_LPC2XXX_REG_TxMCR_MR0_RESET);
151
152     //set prescale register to 0
153     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxPR, 0);                     
154
155     // Enable counter
156     HAL_WRITE_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTCR, 1);
157
158     // Wait for the match
159     do {
160         HAL_READ_UINT32(timer+CYGARC_HAL_LPC2XXX_REG_TxTC, stat);
161     } while (stat < ticks);
162 }
163
164 // -------------------------------------------------------------------------
165 // Hardware init
166
167 // Return value of VPBDIV register. According to errata doc
168 // we need to read twice consecutively to get correct value
169 cyg_uint32 lpc_get_vpbdiv(void)
170 {   
171     cyg_uint32 vpbdiv_reg;
172         
173     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
174                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv_reg);
175     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
176                     CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv_reg);
177
178     return (vpbdiv_reg);
179 }
180
181 // Set the VPBDIV register. The vpb bits are 1:0 and the xclk bits are 5:4. The
182 // mapping of values passed to this routine to field values is:
183 //       4 = divide by 4 (register bits 00)
184 //       2 = divide by 2 (register bits 10)
185 //       1 = divide by 1 (register bits 01)
186 // This routine assumes that only these values can occur. As they are
187 // generated in the CDL hopefully this should be the case. Fortunately
188 // writing 11 merely causes the previous value to be retained.
189 void lpc_set_vpbdiv(int vpbdiv, int xclkdiv)
190 {
191     CYG_ASSERT(((vpbdiv & 0x3) != 3) && ((xclkdiv & 0x3) != 3),
192                "illegal VPBDIV register value");
193
194     // Update VPBDIV register
195 #ifdef CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX
196     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE +
197                      CYGARC_HAL_LPC2XXX_REG_VPBDIV,
198                      ((xclkdiv & 0x3) << 4) | (vpbdiv & 0x3));
199 #else
200     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
201                      CYGARC_HAL_LPC2XXX_REG_VPBDIV, vpbdiv & 0x3);
202 #endif
203 }
204
205 // Perform variant setup. This optionally calls into the platform
206 // HAL if it has defined HAL_PLF_HARDWARE_INIT.
207 void hal_hardware_init(void)
208 {
209 #ifdef CYGHWR_HAL_ARM_LPC2XXX_FAMILY_LPC22XX
210     lpc_set_vpbdiv(CYGNUM_HAL_ARM_LPC2XXX_VPBDIV,
211                    CYGNUM_HAL_ARM_LPC2XXX_XCLKDIV);
212 #else
213     lpc_set_vpbdiv(CYGNUM_HAL_ARM_LPC2XXX_VPBDIV, 1);
214 #endif
215
216     //
217     // 0xFFFFFFFF indicates that this is a non vectored ISR
218     // This is the default setting for all  interrupts
219     //
220     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
221                      CYGARC_HAL_LPC2XXX_REG_VICDEFVECTADDR, 0xFFFFFFFF);
222
223 #ifdef HAL_PLF_HARDWARE_INIT
224     // Perform any platform specific initializations
225     HAL_PLF_HARDWARE_INIT();
226 #endif
227
228     // Set up eCos/ROM interfaces
229     hal_if_init();
230 }
231
232 // -------------------------------------------------------------------------
233 // This routine is called to respond to a hardware interrupt (IRQ).  It
234 // should interrogate the hardware and return the IRQ vector number.
235 int hal_IRQ_handler(void)
236 {
237     cyg_uint32 irq_num;
238     
239     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
240                     CYGARC_HAL_LPC2XXX_REG_VICVECTADDR, irq_num);
241     //
242     // if this is a non vectored ISR then we need to find out which interrupt 
243     // caused the IRQ
244     //      
245     if (0xFFFFFFFF == irq_num)
246     {
247         cyg_uint32 irq_stat;
248         
249         // Find out which interrupt caused the IRQ. This picks the lowest
250         // if there are more than 1.
251         HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
252                         CYGARC_HAL_LPC2XXX_REG_VICIRQSTAT, irq_stat);
253         irq_num = 0;
254         while (!(irq_stat & 0x01))
255         {
256             irq_stat >>= 1;     
257             irq_num++;
258         }
259         
260         // If not a valid interrrupt source, treat as spurious interrupt    
261         if (irq_num < CYGNUM_HAL_ISR_MIN || irq_num > CYGNUM_HAL_ISR_MAX)
262         {
263             irq_num = CYGNUM_HAL_INTERRUPT_NONE;
264         }
265     } // if (0xFFFFFFFF == irq_num)
266     
267     return (irq_num);
268 }
269
270 // -------------------------------------------------------------------------
271 // Interrupt control
272 //
273
274 // Block the the interrupt associated with the vector
275 void hal_interrupt_mask(int vector)
276 {
277     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
278                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
279
280     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
281                      CYGARC_HAL_LPC2XXX_REG_VICINTENCLEAR, 1 << vector);
282 }
283
284 // Unblock the the interrupt associated with the vector
285 void hal_interrupt_unmask(int vector)
286 {
287     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
288                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
289
290     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
291                      CYGARC_HAL_LPC2XXX_REG_VICINTENABLE, 1 << vector);
292 }
293
294 // Acknowledge the the interrupt associated with the vector. This
295 // clears the interrupt but may result in another interrupt being
296 // delivered
297 void hal_interrupt_acknowledge(int vector)
298 {
299
300     // External interrupts have to be cleared from the EXTINT register
301     if (vector >= CYGNUM_HAL_INTERRUPT_EINT0 &&
302         vector <= CYGNUM_HAL_INTERRUPT_EINT3)
303       {
304         // Map int vector to corresponding bit (0..3)
305         vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
306         
307         // Clear the external interrupt
308         HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
309                          CYGARC_HAL_LPC2XXX_REG_EXTINT, vector);
310       }
311     
312     // Acknowledge interrupt in the VIC
313     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
314                      CYGARC_HAL_LPC2XXX_REG_VICVECTADDR, 0);  
315 }
316
317 // This provides control over how an interrupt signal is detected.
318 // Options are between level or edge sensitive (level) and high/low
319 // level or rising/falling edge triggered (up).
320 //
321 // This should be simple, but unfortunately on some processor revisions,
322 // it trips up on two errata issues (for the LPC2294 Rev.A these are
323 // EXTINT.1 and VPBDIV.1) and so on these devices a somewhat convoluted
324 // sequence in order to work properly. There is nothing in the errata
325 // sequence that won't work on a processor without these issues.
326 void hal_interrupt_configure(int vector, int level, int up)
327 {
328     cyg_uint32 regval, saved_vpbdiv;
329
330     // Only external interrupts are configurable        
331     CYG_ASSERT(vector <= CYGNUM_HAL_INTERRUPT_EINT3 &&
332                vector >= CYGNUM_HAL_INTERRUPT_EINT0 , "Invalid vector");
333
334     // Map int vector to corresponding bit (0..3)
335     vector = 1 << (vector - CYGNUM_HAL_INTERRUPT_EINT0);
336     
337 #ifdef CYGHWR_HAL_ARM_LPC2XXX_EXTINT_ERRATA
338     // From discussions with the Philips applications engineers on the
339     // Yahoo LPC2000 forum, it appears that in order up change both
340     // EXTMODE and EXTPOLAR, the operations have to be performed in
341     // two passes as follows:
342     // old=VPBDIV (x2),
343     //     VPBDIV=0, EXTMODE=n, VPBDIV=n, VPBDIV=0, EXTPOLAR=y, VPBDIV=y
344     // VPCDIV=old
345     
346     // Save current VPBDIV register settings
347     saved_vpbdiv = lpc_get_vpbdiv();
348     
349     // Clear VPBDIV register
350     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
351                      CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
352     
353     // Read current mode and update for level (0) or edge detection (1)
354     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
355                     CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
356     if (level)
357       regval &= ~vector;
358     else
359       regval |= vector;
360     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
361                      CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
362     
363     // Set VPBDIV register to same value as mode
364     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
365                      CYGARC_HAL_LPC2XXX_REG_VPBDIV, regval);
366     
367     // Clear VPBDIV register
368     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
369                      CYGARC_HAL_LPC2XXX_REG_VPBDIV, 0);
370     
371     // Read current polarity and update for trigger level or edge
372     // level: high (1), low (0) edge: rising (1), falling (0)
373     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
374                     CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
375     if (up)
376       regval |= vector;
377     else
378       regval &= ~vector;
379     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
380                      CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
381     
382     // Set VPBDIV register to same value as mode
383     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
384                      CYGARC_HAL_LPC2XXX_REG_VPBDIV, regval);
385     
386     // Restore saved VPBDIV register
387     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
388                      CYGARC_HAL_LPC2XXX_REG_VPBDIV, saved_vpbdiv);
389 #else
390     // Read current mode and update for level (0) or edge detection (1)
391     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
392                     CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
393     if (level)
394       regval &= ~vector;
395     else
396       regval |= vector;
397     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
398                      CYGARC_HAL_LPC2XXX_REG_EXTMODE, regval);
399     
400     // Read current polarity and update for trigger level or edge
401     // level: high (1), low (0) edge: rising (1), falling (0)
402     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
403                     CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
404     if (up)
405       regval |= vector;
406     else
407       regval &= ~vector;
408     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
409                      CYGARC_HAL_LPC2XXX_REG_EXTPOLAR, regval);
410 #endif
411     // Clear any spurious interrupt that might have been generated
412     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_SCB_BASE + 
413                      CYGARC_HAL_LPC2XXX_REG_EXTINT, vector);
414 }
415
416 //
417 // We support up to 17 interrupt levels
418 // Interrupts 0 - 15 are vectored interrupt requests. Vectored IRQs have 
419 // the higher priority then non vectored IRQs, but only 16 of the 32 requests 
420 // can be assigned to this category. Any of the 32 requests can be assigned 
421 // to any of the 16 vectored IRQ slots, among which slot 0 has the highest 
422 // priority and slot 15 has the lowest. Priority 16 indicates a non vectored
423 // IRQ.
424 //
425 void hal_interrupt_set_level(int vector, int level)
426 {
427     CYG_ASSERT(vector <= CYGNUM_HAL_ISR_MAX &&
428                vector >= CYGNUM_HAL_ISR_MIN , "Invalid vector");
429     CYG_ASSERT(level >= 0 && level <= 16, "Invalid level");
430     
431     //
432     // If level is < 16 then this is a vectored ISR and we try to write
433     // the vector number of this ISR in the right slot of the vectored 
434     // interrupt controller
435     //
436     if (level < 16)
437     {
438         cyg_uint32 addr_offset =  level << 2;
439         cyg_uint32 reg_val;
440         
441         HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
442                         CYGARC_HAL_LPC2XXX_REG_VICVECTCNTL0 + 
443                         addr_offset, reg_val);
444         CYG_ASSERT((reg_val == 0) || (reg_val == (vector | 0x20)), 
445                    "Priority already used by another vector");
446         HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
447                          CYGARC_HAL_LPC2XXX_REG_VICVECTCNTL0 + 
448                          addr_offset, vector | 0x20);
449         //
450         // We do not store the adress of the ISR here but we store the
451         // vector number The hal_IRQ_handler then can faster determine
452         // the right vector number
453         //
454         HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_VIC_BASE + 
455                          CYGARC_HAL_LPC2XXX_REG_VICVECTADDR0 + 
456                          addr_offset, vector);
457     }     
458 }
459
460 // Use the watchdog to generate a reset
461 void hal_lpc_watchdog_reset(void)
462 {
463     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE + 
464                      CYGARC_HAL_LPC2XXX_REG_WDTC, 0xFF);
465     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE + 
466                      CYGARC_HAL_LPC2XXX_REG_WDMOD, 
467                      CYGARC_HAL_LPC2XXX_REG_WDMOD_WDEN | 
468                      CYGARC_HAL_LPC2XXX_REG_WDMOD_WDRESET);
469
470     // feed WD with the two magic values
471     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE + 
472                      CYGARC_HAL_LPC2XXX_REG_WDFEED, 
473                      CYGARC_HAL_LPC2XXX_REG_WDFEED_MAGIC1);     
474     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_WD_BASE + 
475                      CYGARC_HAL_LPC2XXX_REG_WDFEED, 
476                      CYGARC_HAL_LPC2XXX_REG_WDFEED_MAGIC2);
477     
478     while(1)
479       continue;
480 }
481
482 #ifdef CYGPKG_DEVS_CAN_LPC2XXX
483 //===========================================================================
484 // Do varianat specific CAN initialisation
485 //===========================================================================
486 void hal_lpc_can_init(cyg_uint8 can_chan_no)
487 {
488     typedef struct 
489     {
490         cyg_uint32 pin_mask;
491         cyg_uint16 reg;
492     } canpincfg;
493     
494     static const canpincfg canpincfg_tbl[] =
495     {
496         {0x00040000L, CYGARC_HAL_LPC2XXX_REG_PINSEL1},
497         {0x00014000L, CYGARC_HAL_LPC2XXX_REG_PINSEL1},
498         {0x00001800L, CYGARC_HAL_LPC2XXX_REG_PINSEL1},
499         {0x0F000000L, CYGARC_HAL_LPC2XXX_REG_PINSEL0},
500     };
501     
502     CYG_ASSERT(can_chan_no < 4, "CAN channel number out of bounds");
503     canpincfg *pincfg = (canpincfg *)&canpincfg_tbl[can_chan_no];
504     cyg_uint32 regval;
505     
506     HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + pincfg->reg, regval);
507     regval |= pincfg->pin_mask;
508     HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + pincfg->reg, regval);
509 }
510 #endif // CYGPKG_DEVS_CAN_LPC2XXX
511
512 //--------------------------------------------------------------------------
513 // EOF lpc_misc.c