altos/cc1111: Fix serial 0 option 2 pins definitions
[fw/altos] / src / cc1111 / ao_serial.c
1 /*
2  * Copyright © 2009 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 #if HAS_SERIAL_0
21
22 volatile __xdata struct ao_fifo ao_serial0_rx_fifo;
23 volatile __xdata struct ao_fifo ao_serial0_tx_fifo;
24
25 void
26 ao_serial0_rx_isr(void) __interrupt 2
27 {
28         if (!ao_fifo_full(ao_serial0_rx_fifo))
29                 ao_fifo_insert(ao_serial0_rx_fifo, U0DBUF);
30         ao_wakeup(&ao_serial0_rx_fifo);
31 #if USE_SERIAL_0_STDIN
32         ao_wakeup(&ao_stdin_ready);
33 #endif
34 }
35
36 static __xdata uint8_t ao_serial0_tx_started;
37
38 static void
39 ao_serial0_tx_start(void)
40 {
41         if (!ao_fifo_empty(ao_serial0_tx_fifo) &&
42             !ao_serial0_tx_started)
43         {
44                 ao_serial0_tx_started = 1;
45                 ao_fifo_remove(ao_serial0_tx_fifo, U0DBUF);
46         }
47 }
48
49 void
50 ao_serial0_tx_isr(void) __interrupt 7
51 {
52         UTX0IF = 0;
53         ao_serial0_tx_started = 0;
54         ao_serial0_tx_start();
55         ao_wakeup(&ao_serial0_tx_fifo);
56 }
57
58 char
59 ao_serial0_getchar(void) __critical
60 {
61         char    c;
62         while (ao_fifo_empty(ao_serial0_rx_fifo))
63                 ao_sleep(&ao_serial0_rx_fifo);
64         ao_fifo_remove(ao_serial0_rx_fifo, c);
65         return c;
66 }
67
68 #if USE_SERIAL_0_STDIN
69 char
70 ao_serial0_pollchar(void) __critical
71 {
72         char    c;
73         if (ao_fifo_empty(ao_serial0_rx_fifo))
74                 return AO_READ_AGAIN;
75         ao_fifo_remove(ao_serial0_rx_fifo,c);
76         return c;
77 }
78 #endif
79
80 void
81 ao_serial0_putchar(char c) __critical
82 {
83         while (ao_fifo_full(ao_serial0_tx_fifo))
84                 ao_sleep(&ao_serial0_tx_fifo);
85         ao_fifo_insert(ao_serial0_tx_fifo, c);
86         ao_serial0_tx_start();
87 }
88
89 void
90 ao_serial0_drain(void) __critical
91 {
92         while (!ao_fifo_empty(ao_serial0_tx_fifo))
93                 ao_sleep(&ao_serial0_tx_fifo);
94 }
95
96 void
97 ao_serial0_set_speed(uint8_t speed)
98 {
99         ao_serial0_drain();
100         if (speed > AO_SERIAL_SPEED_57600)
101                 return;
102         U0UCR |= UxUCR_FLUSH;
103         U0BAUD = ao_serial_speeds[speed].baud;
104         U0GCR = ao_serial_speeds[speed].gcr;
105 }
106 #endif /* HAS_SERIAL_0 */
107
108 #if HAS_SERIAL_1
109
110 volatile __xdata struct ao_fifo ao_serial1_rx_fifo;
111 volatile __xdata struct ao_fifo ao_serial1_tx_fifo;
112
113 void
114 ao_serial1_rx_isr(void) __interrupt 3
115 {
116         if (!ao_fifo_full(ao_serial1_rx_fifo))
117                 ao_fifo_insert(ao_serial1_rx_fifo, U1DBUF);
118         ao_wakeup(&ao_serial1_rx_fifo);
119 #if USE_SERIAL1_STDIN
120         ao_wakeup(&ao_stdin_ready);
121 #endif
122 }
123
124 static __xdata uint8_t ao_serial1_tx_started;
125
126 static void
127 ao_serial1_tx_start(void)
128 {
129         if (!ao_fifo_empty(ao_serial1_tx_fifo) &&
130             !ao_serial1_tx_started)
131         {
132                 ao_serial1_tx_started = 1;
133                 ao_fifo_remove(ao_serial1_tx_fifo, U1DBUF);
134         }
135 }
136
137 void
138 ao_serial1_tx_isr(void) __interrupt 14
139 {
140         UTX1IF = 0;
141         ao_serial1_tx_started = 0;
142         ao_serial1_tx_start();
143         ao_wakeup(&ao_serial1_tx_fifo);
144 }
145
146 char
147 ao_serial1_getchar(void) __critical
148 {
149         char    c;
150         while (ao_fifo_empty(ao_serial1_rx_fifo))
151                 ao_sleep(&ao_serial1_rx_fifo);
152         ao_fifo_remove(ao_serial1_rx_fifo, c);
153         return c;
154 }
155
156 #if USE_SERIAL_1_STDIN
157 char
158 ao_serial1_pollchar(void) __critical
159 {
160         char    c;
161         if (ao_fifo_empty(ao_serial1_rx_fifo))
162                 return AO_READ_AGAIN;
163         ao_fifo_remove(ao_serial1_rx_fifo,c);
164         return c;
165 }
166 #endif
167
168 void
169 ao_serial1_putchar(char c) __critical
170 {
171         while (ao_fifo_full(ao_serial1_tx_fifo))
172                 ao_sleep(&ao_serial1_tx_fifo);
173         ao_fifo_insert(ao_serial1_tx_fifo, c);
174         ao_serial1_tx_start();
175 }
176
177 void
178 ao_serial1_drain(void) __critical
179 {
180         while (!ao_fifo_empty(ao_serial1_tx_fifo))
181                 ao_sleep(&ao_serial1_tx_fifo);
182 }
183
184 const __code struct ao_serial_speed ao_serial_speeds[] = {
185         /* [AO_SERIAL_SPEED_4800] = */ {
186                 /* .baud = */ 163,
187                 /* .gcr  = */ (7 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
188         },
189         /* [AO_SERIAL_SPEED_9600] = */ {
190                 /* .baud = */ 163,
191                 /* .gcr  = */ (8 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
192         },
193         /* [AO_SERIAL_SPEED_19200] = */ {
194                 /* .baud = */ 163,
195                 /* .gcr  = */ (9 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
196         },
197         /* [AO_SERIAL_SPEED_57600] = */ {
198                 /* .baud = */ 59,
199                 /* .gcr =  */ (11 << UxGCR_BAUD_E_SHIFT) | UxGCR_ORDER_LSB
200         },
201 };
202
203 void
204 ao_serial1_set_speed(uint8_t speed)
205 {
206         ao_serial1_drain();
207         if (speed > AO_SERIAL_SPEED_57600)
208                 return;
209         U1UCR |= UxUCR_FLUSH;
210         U1BAUD = ao_serial_speeds[speed].baud;
211         U1GCR = ao_serial_speeds[speed].gcr;
212 }
213
214 #endif /* HAS_SERIAL_1 */
215
216 void
217 ao_serial_init(void)
218 {
219 #if HAS_SERIAL_0
220 #if HAS_SERIAL_0_ALT_1
221         /* Set up the USART pin assignment */
222         PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_1;
223
224         P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART0_USART1;
225
226         /* Make the USART pins be controlled by the USART */
227         P0SEL |= (1 << 2) | (1 << 3);
228 #if HAS_SERIAL_0_HW_FLOW
229         P0SEL |= (1 << 4) | (1 << 5);
230 #endif
231 #else
232         /* Set up the USART pin assignment */
233         PERCFG = (PERCFG & ~PERCFG_U0CFG_ALT_MASK) | PERCFG_U0CFG_ALT_2;
234
235         P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI0P1_MASK)) |
236                 (P2SEL_PRI3P1_USART0 | P2SEL_PRI0P1_USART0);
237
238         /* Make the USART pins be controlled by the USART */
239         P1SEL |= (1 << 5) | (1 << 4);
240 #if HAS_SERIAL_0_HW_FLOW
241         P1SEL |= (1 << 3) | (1 << 2);
242 #endif
243 #endif
244
245         /* UART mode with receiver enabled */
246         U0CSR = (UxCSR_MODE_UART | UxCSR_RE);
247
248         /* Pick a 9600 baud rate */
249         ao_serial0_set_speed(AO_SERIAL_SPEED_9600);
250
251         /* Reasonable serial parameters */
252         U0UCR = (UxUCR_FLUSH |
253 #if HAS_SERIAL_0_HW_FLOW
254                  UxUCR_FLOW_ENABLE |
255 #else
256                  UxUCR_FLOW_DISABLE |
257 #endif
258                  UxUCR_D9_EVEN_PARITY |
259                  UxUCR_BIT9_8_BITS |
260                  UxUCR_PARITY_DISABLE |
261                  UxUCR_SPB_1_STOP_BIT |
262                  UxUCR_STOP_HIGH |
263                  UxUCR_START_LOW);
264
265         IEN0 |= IEN0_URX0IE;
266         IEN2 |= IEN2_UTX0IE;
267 #if USE_SERIAL_0_STDIN && !DELAY_SERIAL_0_STDIN
268         ao_add_stdio(ao_serial0_pollchar,
269                      ao_serial0_putchar,
270                      NULL);
271 #endif
272 #endif /* HAS_SERIAL_0 */
273
274 #if HAS_SERIAL_1
275 #if HAS_SERIAL_1_ALT_1
276         /* Set up the USART pin assignment */
277         PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_1;
278
279         P2DIR = (P2DIR & ~P2DIR_PRIP0_MASK) | P2DIR_PRIP0_USART1_USART0;
280
281         /* Make the USART pins be controlled by the USART */
282         P0SEL |= (1 << 5) | (1 << 4);
283 #if HAS_SERIAL_1_HW_FLOW
284         P0SEL |= (1 << 3) | (1 << 2);
285 #endif
286 #else
287         /* Set up the USART pin assignment */
288         PERCFG = (PERCFG & ~PERCFG_U1CFG_ALT_MASK) | PERCFG_U1CFG_ALT_2;
289
290         P2SEL = (P2SEL & ~(P2SEL_PRI3P1_MASK | P2SEL_PRI2P1_MASK)) |
291                 (P2SEL_PRI3P1_USART1 | P2SEL_PRI2P1_USART1);
292
293         /* Make the USART pins be controlled by the USART */
294         P1SEL |= (1 << 6) | (1 << 7);
295         P1SEL |= (1 << 5) | (1 << 4);
296 #endif
297
298         /* UART mode with receiver enabled */
299         U1CSR = (UxCSR_MODE_UART | UxCSR_RE);
300
301         /* Pick a 4800 baud rate */
302         ao_serial1_set_speed(AO_SERIAL_SPEED_4800);
303
304         /* Reasonable serial parameters */
305         U1UCR = (UxUCR_FLUSH |
306 #if HAS_SERIAL_1_HW_FLOW
307                  UxUCR_FLOW_ENABLE |
308 #else
309                  UxUCR_FLOW_DISABLE |
310 #endif
311                  UxUCR_D9_EVEN_PARITY |
312                  UxUCR_BIT9_8_BITS |
313                  UxUCR_PARITY_DISABLE |
314                  UxUCR_SPB_1_STOP_BIT |
315                  UxUCR_STOP_HIGH |
316                  UxUCR_START_LOW);
317
318         IEN0 |= IEN0_URX1IE;
319         IEN2 |= IEN2_UTX1IE;
320
321 #if USE_SERIAL_1_STDIN && !DELAY_SERIAL_1_STDIN
322         ao_add_stdio(ao_serial1_pollchar,
323                      ao_serial1_putchar,
324                      NULL);
325 #endif
326 #endif /* HAS_SERIAL_1 */
327 }