source: arduino-1-6-7/trunk/fuentes/arduino-ide-amd64/hardware/arduino/avr/firmwares/wifishield/wifiHD/src/avr32_spi.c @ 4837

Last change on this file since 4837 was 4837, checked in by daduve, 2 years ago

Adding new version

File size: 11.5 KB
Line 
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);
40void owl_spi_mdelay(uint32_t ms);
41
42int 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
202static 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 */ 
246static 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
301void 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
323void 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
334void 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
360void 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
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}
Note: See TracBrowser for help on using the repository browser.