initial revision
[ucgine.git] / arch / avr / uart / ucg_avr_uart.c
1 /*
2  * Copyright (c) 2015, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
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  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <avr/io.h>
29 #include <ucg_uart.h>
30 #include <ucg_avr_uart.h>
31
32 static void disable_tx_irq(struct ucg_uart *uart)
33 {
34         struct ucg_avr_uart *avr_uart = uart->driver_data;
35         *avr_uart->reg_ucsrb &= ~(1 << avr_uart->bit_udrie);
36 }
37
38 static void enable_tx_irq(struct ucg_uart *uart)
39 {
40         struct ucg_avr_uart *avr_uart = uart->driver_data;
41         *avr_uart->reg_ucsrb |= (1 << avr_uart->bit_udrie);
42 }
43
44 static uint8_t tx_ready(struct ucg_uart *uart)
45 {
46         struct ucg_avr_uart *avr_uart = uart->driver_data;
47         return !!(*avr_uart->reg_ucsra & (1 << avr_uart->bit_udre));
48 }
49
50 static uint8_t rx_ready(struct ucg_uart *uart)
51 {
52         struct ucg_avr_uart *avr_uart = uart->driver_data;
53         return !!(*avr_uart->reg_ucsra & (1 << avr_uart->bit_rxc));
54 }
55
56 static void set_udr(struct ucg_uart *uart, char c)
57 {
58         struct ucg_avr_uart *avr_uart = uart->driver_data;
59         *avr_uart->reg_udr = c;
60 }
61
62 static char get_udr(struct ucg_uart *uart)
63 {
64         struct ucg_avr_uart *avr_uart = uart->driver_data;
65         return *avr_uart->reg_udr;
66 }
67
68 static int set_conf(struct ucg_uart *uart, const struct ucg_uart_config *conf)
69 {
70         struct ucg_avr_uart *avr_uart = uart->driver_data;
71         uint16_t baudreg;
72         uint8_t lo, hi;
73         uint8_t use_u2x = 1; /* always use double speed */
74
75         if (conf->enable == 0) {
76                 *avr_uart->reg_ucsrb = 0;
77                 return 0;
78         }
79
80         if (use_u2x)
81                 baudreg = (F_CPU / (conf->baudrate * 8UL)) - 1;
82         else
83                 baudreg = (F_CPU / (conf->baudrate * 16UL)) - 1;
84
85         lo = (uint8_t)baudreg;
86         hi = (uint8_t)((baudreg >> 8) & 0xF);
87
88         *avr_uart->reg_ubrrl = lo;
89         *avr_uart->reg_ubrrh = hi;
90
91         *avr_uart->reg_ucsra = (
92                 (use_u2x << avr_uart->bit_u2x));
93         *avr_uart->reg_ucsrb = (
94                 (1 << avr_uart->bit_txen) |
95                 (1 << avr_uart->bit_rxen) |
96                 (1 << avr_uart->bit_rxcie));
97
98         return 0;
99 }
100
101 const struct ucg_uart_driver_ops avr_uart_ops = {
102         .disable_tx_irq = disable_tx_irq,
103         .enable_tx_irq = enable_tx_irq,
104         .tx_ready = tx_ready,
105         .rx_ready = rx_ready,
106         .set_udr = set_udr,
107         .get_udr = get_udr,
108         .set_conf = set_conf,
109 };