Switch from GPLv2 to GPLv2+
[fw/altos] / src / attiny / ao_spi_attiny.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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include <ao.h>
20
21 /*
22  * ATtiny USI as a SPI interface
23  */
24
25 /*
26  * Transfer one byte in/out of the USI interface
27  */
28
29 /* Three wire mode */
30 #define SPI_USICR_WM    ((0 << USIWM1) | (1 << USIWM0)) 
31 #define SPI_USICR_CS    ((1 << USICS1) | (0 << USICS0) | (1 << USICLK))
32
33 #define SPI_USICR_FAST_2 ((1 << USIWM0) | (1 << USITC))
34 #define SPI_USICR_FAST_1 ((1 << USIWM0) | (1 << USITC) | (1 << USICLK))
35
36
37 static uint8_t
38 ao_spi_transfer(uint8_t i)
39 {
40         /* Load data register */
41         USIDR = i;
42
43 #if 1
44         USISR = (1 << USIOIF);
45         do {
46                 USICR = SPI_USICR_WM | SPI_USICR_CS | (1 << USITC);
47         } while ((USISR & (1 << USIOIF)) == 0);
48 #else
49         /* 8 clocks */
50         USICR = SPI_USICR_FAST_1;
51         USICR = SPI_USICR_FAST_2;
52
53         USICR = SPI_USICR_FAST_1;
54         USICR = SPI_USICR_FAST_2;
55
56         USICR = SPI_USICR_FAST_1;
57         USICR = SPI_USICR_FAST_2;
58
59         USICR = SPI_USICR_FAST_1;
60         USICR = SPI_USICR_FAST_2;
61
62         USICR = SPI_USICR_FAST_1;
63         USICR = SPI_USICR_FAST_2;
64
65         USICR = SPI_USICR_FAST_1;
66         USICR = SPI_USICR_FAST_2;
67
68         USICR = SPI_USICR_FAST_1;
69         USICR = SPI_USICR_FAST_2;
70
71         USICR = SPI_USICR_FAST_1;
72         USICR = SPI_USICR_FAST_2;
73 #endif
74
75         /* Pull data from the port */
76         return USIDR;
77 }
78
79 /* Send bytes over SPI.
80  *
81  * This just polls; the SPI is set to go as fast as possible,
82  * so using interrupts would take way too long
83  */
84 void
85 ao_spi_send_bus(void __xdata *block, uint16_t len) __reentrant
86 {
87         uint8_t *d = block;
88
89         while (len--)
90                 ao_spi_transfer (*d++);
91 }
92
93 /* Receive bytes over SPI.
94  *
95  * Poll, sending zeros and reading data back
96  */
97 void
98 ao_spi_recv_bus(void __xdata *block, uint16_t len) __reentrant
99 {
100         uint8_t *d = block;
101
102         while (len--)
103                 *d++ = ao_spi_transfer (0xff);
104 }
105
106 /*
107  * Initialize USI
108  *
109  * Chip select is the responsibility of the caller
110  */
111
112 void
113 ao_spi_init(void)
114 {
115 #if 1
116         USICR = (1 << USIWM0) | (1 << USICS1) | (1 << USICLK);
117 #else
118         USICR = SPI_USICR_FAST_2;
119 #endif
120         SPI_DIR &= ~(1 << DDB0);        /* DI */
121         SPI_DIR |= (1 << DDB1);         /* DO */
122         SPI_DIR |= (1 << DDB2);         /* SCLK */
123 }