initial revision
[ucgine.git] / arch / stm32 / uart / ucg_stm32_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 <errno.h>
29
30 #include <ucg_uart.h>
31 #include <ucg_stm32_uart.h>
32
33 static void disable_tx_irq(struct ucg_uart *uart)
34 {
35         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
36
37         stm32_uart->uart->SR &= ~(USART_FLAG_TXE);
38         stm32_uart->uart->CR1 &= ~(USART_CR1_TXEIE);
39 }
40
41 static void enable_tx_irq(struct ucg_uart *uart)
42 {
43         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
44
45         stm32_uart->uart->CR1 |= USART_CR1_TXEIE;
46 }
47
48 static uint8_t tx_ready(struct ucg_uart *uart)
49 {
50         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
51
52         return !!(stm32_uart->uart->SR & USART_FLAG_TXE);
53 }
54
55 static uint8_t rx_ready(struct ucg_uart *uart)
56 {
57         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
58
59         return !!(stm32_uart->uart->SR & USART_FLAG_RXNE);
60 }
61
62 static void set_udr(struct ucg_uart *uart, char c)
63 {
64         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
65
66         stm32_uart->uart->DR = c;
67 }
68
69 static char get_udr(struct ucg_uart *uart)
70 {
71         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
72
73         return stm32_uart->uart->DR;
74 }
75
76 static int set_conf(struct ucg_uart *uart, const struct ucg_uart_config *conf)
77 {
78         USART_InitTypeDef u;
79         GPIO_InitTypeDef gpio;
80         NVIC_InitTypeDef nvic;
81         struct ucg_stm32_uart *stm32_uart = uart->driver_data;
82         int i;
83
84         /* even if it is asked to disable, keep the RCC enabled */
85
86         /* Enable the peripheral clock. */
87         RCC_APB1PeriphClockCmd(stm32_uart->rcc_uart, ENABLE);
88         __asm("dsb");
89
90         /* Enable the peripheral clock for GPIO. */
91         RCC_AHB1PeriphClockCmd(stm32_uart->rcc_gpio, ENABLE);
92         __asm("dsb");
93
94         if (conf->enable == 0) {
95                 USART_ITConfig(stm32_uart->uart, USART_IT_TXE, DISABLE);
96                 USART_ITConfig(stm32_uart->uart, USART_IT_RXNE, DISABLE);
97                 USART_Cmd(stm32_uart->uart, ENABLE);
98
99                 nvic.NVIC_IRQChannel = stm32_uart->irq;
100                 nvic.NVIC_IRQChannelCmd = DISABLE;
101                 NVIC_Init(&nvic);
102                 return 0;
103         }
104
105         if (conf->nbits != 8)
106                 return -EINVAL;
107
108         /* connect to alternate function */
109         for (i = 0; i < 16; i++) {
110                 if ((1 << i) & stm32_uart->gpio_pins) {
111                         GPIO_PinAFConfig(stm32_uart->gpio, i,
112                                 stm32_uart->gpio_af);
113                 }
114         }
115
116         GPIO_StructInit(&gpio);
117         gpio.GPIO_Speed = stm32_uart->gpio_speed;
118
119         /* configure rx and tx */
120         gpio.GPIO_Pin = stm32_uart->gpio_pins;
121         gpio.GPIO_Mode = GPIO_Mode_AF;
122         GPIO_Init(stm32_uart->gpio, &gpio);
123
124         /* USART configuration */
125         u.USART_BaudRate = conf->baudrate;
126         u.USART_WordLength = USART_WordLength_8b;
127         u.USART_StopBits = USART_StopBits_1;
128         u.USART_Parity = USART_Parity_No;
129         u.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
130         u.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
131         USART_Init(stm32_uart->uart, &u);
132
133         /* Enable and set EXTI Interrupt to the defined priority */
134         nvic.NVIC_IRQChannel = stm32_uart->irq;
135         /* nvic.NVIC_IRQChannelPreemptionPriority = stm32_uart->irq_preempt_prio; */
136         /* nvic.NVIC_IRQChannelSubPriority = stm32_uart->irq_sub_prio; */
137         nvic.NVIC_IRQChannelCmd = ENABLE;
138         NVIC_Init(&nvic);
139
140         /* Enable RX interruption */
141         USART_ITConfig(stm32_uart->uart, USART_IT_RXNE, ENABLE);
142
143         /* Enable USART */
144         USART_Cmd(stm32_uart->uart, ENABLE);
145
146         return 0;
147 }
148
149 const struct ucg_uart_driver_ops stm32_uart_ops = {
150         .disable_tx_irq = disable_tx_irq,
151         .enable_tx_irq = enable_tx_irq,
152         .tx_ready = tx_ready,
153         .rx_ready = rx_ready,
154         .set_udr = set_udr,
155         .get_udr = get_udr,
156         .set_conf = set_conf,
157 };