Imported Upstream version 3.0
[debian/gnuradio] / usrp / firmware / src / usrp2 / spi.c
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2004,2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #include "spi.h"
24 #include "usrp_rev2_regs.h"
25
26 static void
27 setup_enables (unsigned char enables)
28 {
29   // Software eanbles are active high.
30   // Hardware enables are active low.
31
32   // Uhh, the CODECs are active low, but the FPGA is active high...
33   enables ^= SPI_ENABLE_FPGA;
34
35   // KLUDGE: This code is fragile, but reasonably fast...
36   // low three bits of enables go into port A
37   USRP_PA = USRP_PA | (0x7 << 3);       // disable FPGA, CODEC_A, CODEC_B
38   USRP_PA ^= (enables & 0x7) << 3;      // enable specified devs
39
40   // high four bits of enables go into port E
41   USRP_PE = USRP_PE | (0xf << 4);       // disable TX_A, RX_A, TX_B, RX_B
42   USRP_PE ^= (enables & 0xf0);          // enable specified devs
43 }
44
45 #define disable_all()   setup_enables (0)
46
47 void
48 init_spi (void)
49 {
50   disable_all ();               /* disable all devs       */
51   bitS_OUT = 0;                 /* idle state has CLK = 0 */
52 }
53
54 #if 0
55 static unsigned char
56 count_bits8 (unsigned char v)
57 {
58   static unsigned char count4[16] = {
59     0,  // 0
60     1,  // 1
61     1,  // 2
62     2,  // 3
63     1,  // 4
64     2,  // 5
65     2,  // 6
66     3,  // 7
67     1,  // 8
68     2,  // 9
69     2,  // a
70     3,  // b
71     2,  // c
72     3,  // d
73     3,  // e
74     4   // f
75   };
76   return count4[v & 0xf] + count4[(v >> 4) & 0xf];
77 }
78
79 #else
80
81 static unsigned char
82 count_bits8 (unsigned char v)
83 {
84   unsigned char count = 0;
85   if (v & (1 << 0)) count++;
86   if (v & (1 << 1)) count++;
87   if (v & (1 << 2)) count++;
88   if (v & (1 << 3)) count++;
89   if (v & (1 << 4)) count++;
90   if (v & (1 << 5)) count++;
91   if (v & (1 << 6)) count++;
92   if (v & (1 << 7)) count++;
93   return count;
94 }
95 #endif
96
97 static void
98 write_byte_msb (unsigned char v);
99
100 static void
101 write_bytes_msb (const xdata unsigned char *buf, unsigned char len);
102
103 static void
104 read_bytes_msb (xdata unsigned char *buf, unsigned char len);
105
106   
107 // returns non-zero if successful, else 0
108 unsigned char
109 spi_read (unsigned char header_hi, unsigned char header_lo,
110           unsigned char enables, unsigned char format,
111           xdata unsigned char *buf, unsigned char len)
112 {
113   if (count_bits8 (enables) > 1)
114     return 0;           // error, too many enables set
115
116   setup_enables (enables);
117
118   if (format & SPI_FMT_LSB){            // order: LSB
119 #if 1
120     return 0;           // error, not implemented
121 #else
122     switch (format & SPI_FMR_HDR_MASK){
123     case SPI_FMT_HDR_0:
124       break;
125     case SPI_FMT_HDR_1:
126       write_byte_lsb (header_lo);
127       break;
128     case SPI_FMT_HDR_2:
129       write_byte_lsb (header_lo);
130       write_byte_lsb (header_hi);
131       break;
132     default:
133       return 0;         // error
134     }
135     if (len != 0)
136       read_bytes_lsb (buf, len);
137 #endif
138   }
139
140   else {                // order: MSB
141
142     switch (format & SPI_FMT_HDR_MASK){
143     case SPI_FMT_HDR_0:
144       break;
145     case SPI_FMT_HDR_1:
146       write_byte_msb (header_lo);
147       break;
148     case SPI_FMT_HDR_2:
149       write_byte_msb (header_hi);
150       write_byte_msb (header_lo);
151       break;
152     default:
153       return 0;         // error
154     }
155     if (len != 0)
156       read_bytes_msb (buf, len);
157   }
158
159   disable_all ();
160   return 1;             // success
161 }
162
163
164 // returns non-zero if successful, else 0
165 unsigned char
166 spi_write (unsigned char header_hi, unsigned char header_lo,
167            unsigned char enables, unsigned char format,
168            const xdata unsigned char *buf, unsigned char len)
169 {
170   setup_enables (enables);
171
172   if (format & SPI_FMT_LSB){            // order: LSB
173 #if 1
174     return 0;           // error, not implemented
175 #else
176     switch (format & SPI_FMR_HDR_MASK){
177     case SPI_FMT_HDR_0:
178       break;
179     case SPI_FMT_HDR_1:
180       write_byte_lsb (header_lo);
181       break;
182     case SPI_FMT_HDR_2:
183       write_byte_lsb (header_lo);
184       write_byte_lsb (header_hi);
185       break;
186     default:
187       return 0;         // error
188     }
189     if (len != 0)
190       write_bytes_lsb (buf, len);
191 #endif
192   }
193
194   else {                // order: MSB
195
196     switch (format & SPI_FMT_HDR_MASK){
197     case SPI_FMT_HDR_0:
198       break;
199     case SPI_FMT_HDR_1:
200       write_byte_msb (header_lo);
201       break;
202     case SPI_FMT_HDR_2:
203       write_byte_msb (header_hi);
204       write_byte_msb (header_lo);
205       break;
206     default:
207       return 0;         // error
208     }
209     if (len != 0)
210       write_bytes_msb (buf, len);
211   }
212
213   disable_all ();
214   return 1;             // success
215 }
216
217 // ----------------------------------------------------------------
218
219 static void
220 write_byte_msb (unsigned char v)
221 {
222   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
223   bitS_OUT = v & 0x1;
224   bitS_CLK = 1;
225   bitS_CLK = 0;
226
227   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
228   bitS_OUT = v & 0x1;
229   bitS_CLK = 1;
230   bitS_CLK = 0;
231
232   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
233   bitS_OUT = v & 0x1;
234   bitS_CLK = 1;
235   bitS_CLK = 0;
236
237   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
238   bitS_OUT = v & 0x1;
239   bitS_CLK = 1;
240   bitS_CLK = 0;
241
242   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
243   bitS_OUT = v & 0x1;
244   bitS_CLK = 1;
245   bitS_CLK = 0;
246
247   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
248   bitS_OUT = v & 0x1;
249   bitS_CLK = 1;
250   bitS_CLK = 0;
251
252   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
253   bitS_OUT = v & 0x1;
254   bitS_CLK = 1;
255   bitS_CLK = 0;
256
257   v = (v << 1) | (v >> 7);      // rotate left (MSB into bottom bit)
258   bitS_OUT = v & 0x1;
259   bitS_CLK = 1;
260   bitS_CLK = 0;
261 }
262
263 static void
264 write_bytes_msb (const xdata unsigned char *buf, unsigned char len)
265 {
266   while (len-- != 0){
267     write_byte_msb (*buf++);
268   }
269 }
270
271 #if 0
272 /*
273  * This is incorrectly compiled by SDCC 2.4.0
274  */
275 static unsigned char
276 read_byte_msb (void)
277 {
278   unsigned char v = 0;
279
280   bitS_CLK = 1;
281   v |= bitS_IN;
282   bitS_CLK = 0;
283
284   v = v << 1;
285   bitS_CLK = 1;
286   v |= bitS_IN;
287   bitS_CLK = 0;
288
289   v = v << 1;
290   bitS_CLK = 1;
291   v |= bitS_IN;
292   bitS_CLK = 0;
293
294   v = v << 1;
295   bitS_CLK = 1;
296   v |= bitS_IN;
297   bitS_CLK = 0;
298
299   v = v << 1;
300   bitS_CLK = 1;
301   v |= bitS_IN;
302   bitS_CLK = 0;
303
304   v = v << 1;
305   bitS_CLK = 1;
306   v |= bitS_IN;
307   bitS_CLK = 0;
308
309   v = v << 1;
310   bitS_CLK = 1;
311   v |= bitS_IN;
312   bitS_CLK = 0;
313
314   v = v << 1;
315   bitS_CLK = 1;
316   v |= bitS_IN;
317   bitS_CLK = 0;
318
319   return v;
320 }
321 #else
322 static unsigned char
323 read_byte_msb (void) _naked
324 {
325   _asm
326         clr     a
327
328         setb    _bitS_CLK
329         mov     c, _bitS_IN
330         rlc     a
331         clr     _bitS_CLK
332
333         setb    _bitS_CLK
334         mov     c, _bitS_IN
335         rlc     a
336         clr     _bitS_CLK
337
338         setb    _bitS_CLK
339         mov     c, _bitS_IN
340         rlc     a
341         clr     _bitS_CLK
342
343         setb    _bitS_CLK
344         mov     c, _bitS_IN
345         rlc     a
346         clr     _bitS_CLK
347
348         setb    _bitS_CLK
349         mov     c, _bitS_IN
350         rlc     a
351         clr     _bitS_CLK
352
353         setb    _bitS_CLK
354         mov     c, _bitS_IN
355         rlc     a
356         clr     _bitS_CLK
357
358         setb    _bitS_CLK
359         mov     c, _bitS_IN
360         rlc     a
361         clr     _bitS_CLK
362
363         setb    _bitS_CLK
364         mov     c, _bitS_IN
365         rlc     a
366         clr     _bitS_CLK
367
368         mov     dpl,a
369         ret
370   _endasm;
371 }
372 #endif
373
374 static void
375 read_bytes_msb (xdata unsigned char *buf, unsigned char len)
376 {
377   while (len-- != 0){
378     *buf++ = read_byte_msb ();
379   }
380 }
381