altos: Add support for multiple SPI busses and sharing device drivers
[fw/altos] / src / avr / ao_spi_usart.c
1 /*
2  * Copyright © 2011 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "ao.h"
19
20 /*
21  * Atmega32u4 USART in MSPIM (master SPI mode)
22  */
23
24 __xdata uint8_t ao_spi_mutex;
25
26 /* Send bytes over SPI.
27  *
28  * This just polls; the SPI is set to go as fast as possible,
29  * so using interrupts would take way too long
30  */
31 void
32 ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
33 {
34         uint8_t *d = block;
35
36         while (len--) {
37                 while (!(UCSR1A & (1 << UDRE1)));
38                 UDR1 = *d++;
39                 while (!(UCSR1A & (1 << RXC1)));
40                 (void) UDR1;
41         }
42 }
43
44 /* Receive bytes over SPI.
45  *
46  * Poll, sending zeros and reading data back
47  */
48 void
49 ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
50 {
51         uint8_t *d = block;
52
53         /* Clear any pending data */
54         while (UCSR1A & (1 << RXC1))
55                 (void) UDR1;
56         
57         while (len--) {
58                 while (!(UCSR1A & (1 << UDRE1)));
59                 UDR1 = 0;
60                 while (!(UCSR1A & (1 << RXC1)));
61                 *d++ = UDR1;
62         }
63 }
64
65 /*
66  * Initialize USART0 for SPI using config alt 2
67  *
68  *      MO      P1_5
69  *      MI      P1_4
70  *      CLK     P1_3
71  *
72  * Chip select is the responsibility of the caller
73  */
74
75 #define XCK1_DDR        DDRD
76 #define XCK1_PORT       PORTD
77 #define XCK1            PORTD5
78 #define XMS1_DDR        DDRE
79 #define XMS1_PORT       PORTE
80 #define XMS1            PORTE6
81
82 void
83 ao_spi_init(void)
84 {
85         /* Ensure the USART is powered */
86         PRR1 &= ~(1 << PRUSART1);
87
88         /*
89          * Set pin directions
90          */
91         XCK1_DDR |= (1 << XCK1);
92
93         /* Clear chip select (which is negated) */
94         XMS1_PORT |= (1 < XMS1);
95         XMS1_DDR |= (1 << XMS1);
96
97         /* Set baud register to zero (required before turning transmitter on) */
98         UBRR1 = 0;
99
100         UCSR1C = ((0x3 << UMSEL10) |    /* Master SPI mode */
101                   (0 << UCSZ10) |       /* SPI mode 0 */
102                   (0 << UCPOL1));       /* SPI mode 0 */
103
104         /* Enable transmitter and receiver */
105         UCSR1B = ((1 << RXEN1) |
106                   (1 << TXEN1));
107
108         /* It says that 0 is a legal value; we'll see... */
109         UBRR1 = 0;
110 }