]> rtime.felk.cvut.cz Git - lincan.git/blob - embedded/arch/arm/mach-lpc21xx/libs/hal/hal.c
a983e954915d3bb7084bd52d0c3f5eac5cb1577f
[lincan.git] / embedded / arch / arm / mach-lpc21xx / libs / hal / hal.c
1 #include <system_def.h>
2 #include <hal_ints.h>
3 #include <hal_intr.h>
4 #include <types.h>
5  
6 // -------------------------------------------------------------------------
7 // Hardware init
8
9 // Return value of VPBDIV register. According to errata doc
10 // we need to read twice consecutively to get correct value
11 uint32_t lpc_get_vpbdiv(void)
12 {   
13     uint32_t vpbdiv_reg;
14
15     vpbdiv_reg=VPBDIV;
16     vpbdiv_reg=VPBDIV;
17
18     return (vpbdiv_reg);
19 }
20
21
22 // -------------------------------------------------------------------------
23 // This routine is called to respond to a hardware interrupt (IRQ).  It
24 // should interrogate the hardware and return the IRQ vector number.
25 int hal_IRQ_handler(void)
26 {
27     uint32_t irq_num, irq_stat;
28
29     irq_stat=VICIRQStatus;
30     for (irq_num = 0; irq_num < 32; irq_num++)
31       if (irq_stat & (1 << irq_num))
32         break;
33     
34     // If not a valid interrrupt source, treat as spurious interrupt    
35     if (irq_num < HAL_ISR_MIN || irq_num > HAL_ISR_MAX)
36       irq_num = HAL_INTERRUPT_NONE;
37     
38     return (irq_num);
39 }
40
41
42 // -------------------------------------------------------------------------
43 // Interrupt control
44 //
45
46 // Block the the interrupt associated with the vector
47 void hal_interrupt_mask(int vector)
48 {
49     VICIntEnClear = 1 << vector;
50 }
51
52 // Unblock the the interrupt associated with the vector
53 void hal_interrupt_unmask(int vector)
54 {
55     VICIntEnable = 1 << vector;
56 }
57
58 // Acknowledge the the interrupt associated with the vector. This
59 // clears the interrupt but may result in another interrupt being
60 // delivered
61 void hal_interrupt_acknowledge(int vector)
62 {
63
64     // External interrupts have to be cleared from the EXTINT register
65     if (vector >= HAL_INTERRUPT_EINT0 &&
66         vector <= HAL_INTERRUPT_EINT3)
67       {
68         // Map int vector to corresponding bit (0..3)
69         vector = 1 << (vector - HAL_INTERRUPT_EINT0);
70                 
71         // Clear the external interrupt
72         EXTINT=vector;
73       }
74     
75     // Acknowledge interrupt in the VIC
76     VICVectAddr=0;
77 }
78
79 // This provides control over how an interrupt signal is detected.
80 // Options are between level or edge sensitive (level) and high/low
81 // level or rising/falling edge triggered (up).
82 //
83 // This should be simple, but unfortunately on some processor revisions,
84 // it trips up on two errata issues (for the LPC2294 Rev.A these are
85 // EXTINT.1 and VPBDIV.1) and so on these devices a somewhat convoluted
86 // sequence in order to work properly. There is nothing in the errata
87 // sequence that won't work on a processor without these issues.
88 void hal_interrupt_configure(int vector, int level, int up)
89 {
90     uint32_t regval;
91 #ifdef HAL_ARM_LPC2XXX_EXTINT_ERRATA
92     uint32_t saved_vpbdiv;
93 #endif
94
95     // Map int vector to corresponding bit (0..3)
96     vector = 1 << (vector - HAL_INTERRUPT_EINT0);
97     
98 #ifdef HAL_ARM_LPC2XXX_EXTINT_ERRATA
99     // From discussions with the Philips applications engineers on the
100     // Yahoo LPC2000 forum, it appears that in order up change both
101     // EXTMODE and EXTPOLAR, the operations have to be performed in
102     // two passes as follows:
103     // old=VPBDIV (x2),
104     //     VPBDIV=0, EXTMODE=n, VPBDIV=n, VPBDIV=0, EXTPOLAR=y, VPBDIV=y
105     // VPCDIV=old
106     
107     // Save current VPBDIV register settings
108     saved_vpbdiv = lpc_get_vpbdiv();
109     
110     // Clear VPBDIV register
111     VPBDIV=0;
112     
113     // Read current mode and update for level (0) or edge detection (1)
114     regval=EXTMODE;
115     if (level)
116       regval &= ~vector;
117     else
118       regval |= vector;
119     EXTMODE=regval;
120     
121     // Set VPBDIV register to same value as mode
122     VPBDIV=regval;
123     
124     // Clear VPBDIV register
125     VPBDIV=0;
126     
127     // Read current polarity and update for trigger level or edge
128     // level: high (1), low (0) edge: rising (1), falling (0)
129     regval=EXTPOLAR;
130     if (up)
131       regval |= vector;
132     else
133       regval &= ~vector;
134     EXTPOLAR=regval;
135       
136     
137     // Set VPBDIV register to same value as mode
138     VPBDIV=regval;
139     
140     // Restore saved VPBDIV register
141     VPBDIV=saved_vpbdiv;
142 #else
143     // Read current mode and update for level (0) or edge detection (1)
144     regval=EXTMODE;
145     if (level)
146       regval &= ~vector;
147     else
148       regval |= vector;
149     EXTMODE=regval;
150     
151     // Read current polarity and update for trigger level or edge
152     // level: high (1), low (0) edge: rising (1), falling (0)
153     regval=EXTPOLAR;
154     if (up)
155       regval |= vector;
156     else
157       regval &= ~vector;
158     EXTPOLAR=regval;
159 #endif
160     // Clear any spurious interrupt that might have been generated
161     EXTINT=vector;
162 }
163
164 // Change interrupt level. This is a non-operation on the LPC2XXX
165 void hal_interrupt_set_level(int vector, int level)
166 {
167 }
168
169 uint32_t hal_default_isr(int vector, uint32_t data)
170 {
171   return 0;
172 }
173
174 uint32_t hal_interrupt_handlers[HAL_ISR_COUNT]={[0 ... HAL_ISR_COUNT-1]=(uint32_t)hal_default_isr};
175 uint32_t hal_interrupt_data[HAL_ISR_COUNT];
176
177 void irq_handler_resolver(void) __attribute__ ((interrupt));
178 void irq_handler_resolver(void)
179 {
180   int v;
181   uint32_t f,d;
182
183   v=hal_IRQ_handler();
184   if (v==HAL_INTERRUPT_NONE) return;
185   f=hal_interrupt_handlers[v];
186   d=hal_interrupt_data[v];
187   ((hal_isr)f)(v,d);  
188   hal_interrupt_acknowledge(v);
189 }