1 /*! \page License
2  * Copyright (C) 2009, H&D Wireless AB All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  * 1. Redistributions of source code must retain the above copyright notice,
8  * this list of conditions and the following disclaimer.
9  *
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * 3. The name of H&D Wireless AB may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY H&D WIRELESS AB ``AS IS'' AND ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY AND
20  * SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT,
21  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include <gpio.h>
29 #include <intc.h>
30 #include <string.h>
31 #include <stdint.h>
32 #include <stdlib.h>
33 #include <wl_spi.h>
34 #include <printf-stdarg.h>
35 #include <board_init.h>
36 
37 #define ARRAY_SIZE(a) sizeof(a) / sizeof(a[0])
38 
39 __attribute__((__interrupt__)) void avr32_irq_handler(void);
40 void owl_spi_mdelay(uint32_t ms);
41 
owl_spi_init(U8 * flags)42 int owl_spi_init(U8 *flags)
43 {
44 #ifdef _ASSERT_ENABLE_ /* To silence warning if Assert() macro is empty */
45         volatile avr32_pm_t *pm = &AVR32_PM;
46 #endif
47 
48         volatile avr32_spi_t *spi = &WL_SPI;
49 #if WL_SPI_CS == 1
50         volatile avr32_spi_csr1_t* CSR = &spi->CSR1;
51 #elif WL_SPI_CS == 2
52         volatile avr32_spi_csr2_t* CSR = &spi->CSR2;
53 #elif WL_SPI_CS == 3
54         volatile avr32_spi_csr3_t* CSR = &spi->CSR3;
55 #elif SPI_CS == 0
56         volatile avr32_spi_csr0_t* CSR = &spi->CSR0;
57 #endif
58 
59 #ifndef WITH_NO_DMA
60 	volatile avr32_pdca_channel_t *pdca_tx = &AVR32_PDCA.channel[0];
61 	volatile avr32_pdca_channel_t *pdca_rx = &AVR32_PDCA.channel[1];
62 #endif
63 
64 #ifndef WL_IRQ_PIN
65         *flags = SPI_FLAG_POLL;
66 #else
67         *flags = 0;
68 #endif
69 
70 
71 #ifdef WL_IRQ_PIN
72         /* input, irq */
73         gpio_enable_gpio_pin(WL_IRQ_PIN);
74         gpio_enable_pin_pull_up(WL_IRQ_PIN);
75 #endif
76 
77 //#ifdef WL_RESET_PIN
78 //        /* reset pin */
79 //        gpio_enable_gpio_pin(WL_RESET_PIN);
80 //        gpio_set_gpio_pin(WL_RESET_PIN);
81 //#endif
82 
83 
84 #ifdef WL_POWER_PIN
85         /* power off the device */
86         gpio_enable_gpio_pin(WL_POWER_PIN);
87         gpio_set_gpio_pin(WL_POWER_PIN);
88 #endif
89 
90 #ifdef WL_SHUTDOWN_PIN
91         gpio_enable_gpio_pin(WL_SHUTDOWN_PIN);
92 
93 #ifdef WL_NO_INTERNAL_RESET  /* never defined for SPB104/SPB105 */
94         gpio_clr_gpio_pin(WL_SHUTDOWN_PIN);
95 #endif
96 
97 #ifdef WL_EXTERNAL_RESET
98         gpio_enable_gpio_pin(WL_RESET_PIN);
99 #endif
100 
101 #endif /* WL_SHUTDOWN_PIN */
102 
103 #ifdef WL_POWER_PIN
104         /* power on the device */
105         gpio_clr_gpio_pin(WL_POWER_PIN);
106 #endif
107 
108 #ifdef WL_SHUTDOWN_PIN
109 
110 #ifdef WL_NO_INTERNAL_RESET /* never defined for SPB104/SPB105 */
111         owl_spi_mdelay(5);
112         gpio_set_gpio_pin(WL_SHUTDOWN_PIN);
113 
114 #elif WL_EXTERNAL_RESET
115         owl_spi_mdelay(5);
116         gpio_set_gpio_pin(WL_SHUTDOWN_PIN);
117 
118         owl_spi_mdelay(20);
119         //delay_ms(10);	//2ms
120 
121          /* reset pin */
122         gpio_set_gpio_pin(WL_RESET_PIN);
123 
124 #else
125 
126         /* The shutdown pin will go high once the device is powered */
127         {
128 #define SHUTDOWN_TIMEOUT 350
129                 uint32_t shutdown_timer = 0;
130                 while (gpio_get_pin_value(WL_SHUTDOWN_PIN) == 0) {
131                         if (shutdown_timer > SHUTDOWN_TIMEOUT)
132                         {
133                         	printk("Timeout WL Shutdown\n");
134                         	 return -1;
135                         }
136                         owl_spi_mdelay(5);
137                         shutdown_timer += 5;
138                 }
139         }
140 #endif /* WL_NO_INTERNAL_RESET */
141 
142 #else
143         /* We need to make a guess about the time needed to power the device,
144          * this will depend on the hardware design.
145          */
146         owl_spi_mdelay(5);
147 #endif /* WL_SHUTDOWN_PIN */
148 
149         /* Note: SPI0 clock enabled at reset in pm->pbamask (see 13.6.3) */
150         Assert(pm->pbamask & (1 << 5));
151 
152         /* Note: GPIO clock enabled at reset in pm->pbamask (see 13.6.3) */
153         Assert(pm->pbamask & (1 << 1));
154 #ifdef WL_IRQ_PIN
155         /* 22.4.7: "In every port there are four interrupt lines
156          * connected to the interrupt controller. Every eigth
157          * interrupts in the port are ored together to form an
158          * interrupt line."
159          *
160          * WL_IRQ_# = (WL_IRQ_PIN / 32) * 4 + (WL_IRQ_PIN / 8) % 4
161          * 62 => 1 * 4 + 3 = 7
162          */
163         INTC_register_interrupt(&avr32_irq_handler, WL_IRQ, AVR32_INTC_INT0);
164 #endif
165 
166 #ifndef WITH_NO_DMA
167         INTC_register_interrupt(&avr32_irq_handler, AVR32_PDCA_IRQ_0,
168                                 AVR32_INTC_INT0);
169         INTC_register_interrupt(&avr32_irq_handler, AVR32_PDCA_IRQ_1,
170                                 AVR32_INTC_INT0);
171         pdca_tx->IER.terr = 1;
172         pdca_rx->IER.terr = 1;
173 #endif
174 
175 #ifdef WL_SPI_CLOCK_DIVIDER
176         CSR->scbr = WL_SPI_CLOCK_DIVIDER;
177 #else
178         CSR->scbr = 2;
179 #endif
180 
181         /* Use max width of TDR register, 16 bit transfers */
182 	CSR->bits = 0x8;
183 
184         /* Make sure that we can hold CS low until transfer is completed, e.g
185          * LASTXFER is set in TDR.
186          */
187         CSR->csaat = 1;
188 
189         /* NRG component requires clock polarity high */
190         CSR->cpol = 1;
191 
192 
193 #ifdef WL_IRQ_PIN
194         /* make sure to clear any pending bits in ifr here. */
195         gpio_clear_pin_interrupt_flag(WL_IRQ_PIN);
196 #endif
197 
198         return 0;
199 }
200 
201 #ifndef WITH_NO_DMA
dma_txrx(const U8 * in,U8 * out,U16 len)202 static void dma_txrx(const U8* in, U8* out, U16 len)
203 {
204 	volatile avr32_pdca_channel_t *pdca_tx = &AVR32_PDCA.channel[0];
205 	volatile avr32_pdca_channel_t *pdca_rx = &AVR32_PDCA.channel[1];
206 
207         /* setup tx */
208         pdca_tx->mar = (U32) in;
209         pdca_tx->PSR.pid = WL_PDCA_PID_TX;
210 	pdca_tx->tcr = len / 2;
211 	pdca_tx->MR.size = 1; /* 2-byte */
212         pdca_tx->IER.trc = 1;
213 
214         /* setup rx */
215         pdca_rx->mar = (U32) out;
216 	pdca_rx->PSR.pid = WL_PDCA_PID_RX;
217 	pdca_rx->tcr = len / 2;
218 	pdca_rx->MR.size = 1; /* 2-byte */
219         pdca_rx->IER.trc = 1;
220 
221         /* start dma's. for some reason rx must be started prior to tx */
222 	pdca_rx->CR.ten = 1;
223 	pdca_tx->CR.ten = 1;
224 
225         /* blocking wait until transfer is completed */
226         while (!(pdca_tx->ISR.trc && pdca_rx->ISR.trc));
227 }
228 #endif
229 
230 /* access data using byte pointers since we might get unaligned
231  * data from lwip. The cpu will issue a data abort if we try
232  * to access data which is not properly aligned. See data sheet.
233  *
234  * Note that fifo_txrx() doesn't handle the case where len is not a
235  * multiple of two bytes properly.
236  *
237  * However, there is no actual case where len is odd at the same time
238  * as the "out" pointer is non-NULL; therefore I think that in practice,
239  * we'll not write beyond the end of the "out" array.
240  *
241  * The extra unknown byte fetched from the in pointer will be discarded
242  * by the device since a length field included in the packet header will inform
243  * the device of the actual number of valid bytes (this implementation is
244  * kind of hidden inside the library).
245  */
fifo_txrx(const U8 * in,U8 * out,U16 len)246 static void fifo_txrx(const U8 *in, U8* out, U16 len)
247 {
248         volatile avr32_spi_t *spi = &WL_SPI;
249         UnionCPtr in_ptr;
250         UnionPtr out_ptr;
251         U32 sr;
252 
253         Assert(len);
254 
255         in_ptr.u8ptr = in;
256         out_ptr.u8ptr = out;
257 
258         while (len) {
259                 U16 rdr;
260 		union {
261 			avr32_spi_tdr_t TDR;
262 			U32 tdr;
263 		} reg = { { 0 } };
264 
265                 while (!spi->SR.tdre);
266                 while (!spi->SR.txempty);
267 
268 		/* prepare tx data register contents */
269                 if (in_ptr.u8ptr) {
270                         reg.TDR.td |= (in_ptr.u8ptr[0] << 8) | in_ptr.u8ptr[1];
271                         in_ptr.u16ptr++;
272                 }
273                 else
274                         reg.TDR.td |= 0xffff;
275 
276 		/* perform tx */
277                 spi->tdr = reg.tdr;
278 
279 		/* wait until rx is ready */
280                 while (!spi->SR.rdrf);
281 
282 		/* fetch rx data */
283                 rdr = spi->RDR.rd;
284                 if (out_ptr.u8ptr) {
285                         out_ptr.u8ptr[0] = (rdr >> 8) & 0xff;
286                         out_ptr.u8ptr[1] = rdr & 0xff;
287                         out_ptr.u16ptr++;
288                 }
289 
290                 if (len >= 2)
291                         len -= 2;
292                 else
293                         len = 0;
294         }
295 
296         sr = spi->sr;
297         Assert(!(sr & AVR32_SPI_SR_OVRES_MASK));
298         Assert(!(sr & AVR32_SPI_SR_MODF_MASK));
299 }
300 
owl_spi_txrx(const U8 * in,U8 * out,U16 len)301 void owl_spi_txrx(const U8 *in, U8* out, U16 len)
302 {
303 #ifndef WITH_NO_DMA
304         static uint8_t buf[MAX_BLOCK_LEN];
305 
306         /* unaligned data or odd number of bytes, then skip dma */
307         if ((U32) in % 4 || (U32) out % 4 || len % 2) {
308                 fifo_txrx(in, out, len);
309         } else {
310                 if (in == NULL) {
311                         memset(buf, 0xff, len);
312                         in = buf;
313                 } else if (out == NULL) {
314                         out = buf;
315                 }
316                 dma_txrx(in, out, len);
317         }
318 #else
319         fifo_txrx(in, out, len);
320 #endif
321 }
322 
owl_spi_irq(U8 enable)323 void owl_spi_irq(U8 enable)
324 {
325 #ifdef WL_IRQ_PIN
326 
327         if (enable)
328                 gpio_enable_pin_interrupt(WL_IRQ_PIN, GPIO_PIN_CHANGE);
329         else
330                 gpio_disable_pin_interrupt(WL_IRQ_PIN);
331 #endif
332 }
333 
owl_spi_cs(U8 enable)334 void owl_spi_cs(U8 enable)
335 {
336 	volatile avr32_spi_t *spi = &WL_SPI;
337 
338         /*
339          * PCS = xxx0 => NPCS[3:0] = 1110
340          * PCS = xx01 => NPCS[3:0] = 1101
341          * PCS = x011 => NPCS[3:0] = 1011
342          * PCS = 0111 => NPCS[3:0] = 0111
343          * PCS = 1111 => forbidden (no peripheral is selected)
344          */
345 
346 	if (enable)
347 #if WL_SPI_CS == 2
348 	        spi->MR.pcs = 0x3; /* cs2 */
349 #elif WL_SPI_CS == 1
350                 spi->MR.pcs = 0x1; /* cs1 */
351 #elif WL_SPI_CS == 3
352                 spi->MR.pcs = 0x7; /* cs3 */
353 #elif WL_SPI_CS == 0
354                 spi->MR.pcs = 0x0; /* cs0 */
355 #endif
356 	else
357 		spi->MR.pcs = 0xf;
358 }
359 
owl_spi_mdelay(uint32_t ms)360 void owl_spi_mdelay(uint32_t ms)
361 {
362         volatile int a = 0;
363         int i;
364         for (i = 0; i < ms * 5000; i++)
365                 a++;
366 }
367 
avr32_irq_handler(void)368 __attribute__((__interrupt__)) void avr32_irq_handler(void)
369 {
370 #ifndef WITH_NO_DMA
371 	volatile avr32_pdca_channel_t *pdca_tx = &AVR32_PDCA.channel[0];
372 	volatile avr32_pdca_channel_t *pdca_rx = &AVR32_PDCA.channel[1];
373 
374         /* tx xfer complete */
375 	if (pdca_tx->IMR.trc && pdca_tx->ISR.trc) {
376                 pdca_tx->IDR.trc = 1;
377                 pdca_tx->CR.tdis = 1;  /* disable tx xfer */
378 	}
379 
380         /* rx xfer complete */
381 	if (pdca_rx->IMR.trc && pdca_rx->ISR.trc) {
382                 pdca_rx->IDR.trc = 1;
383                 pdca_rx->CR.tdis = 1;  /* disable rx xfer */
384 	}
385 #endif
386 
387 #ifdef WL_IRQ_PIN
388         if (gpio_get_pin_interrupt_flag(WL_IRQ_PIN)) {
389 		gpio_clear_pin_interrupt_flag(WL_IRQ_PIN);
390                 wl_spi_irq();
391 	}
392 #endif
393 
394 }
395