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