uart->out_buff cannot be NULL, remove this tests.
[lpc82x] / drivers / serial.c
1 /****************************************************************************
2  *  drivers/serial.c
3  *
4  * Copyright 2012 Nathael Pajani <nathael.pajani@ed3l.fr>
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  *************************************************************************** */
23 /***************************************************************************** */
24 /*                UARTs                                                        */
25 /***************************************************************************** */
26 /* UART driver for the integrated UARTs of the LPC82x.
27  * Refer to LPC82x documentation (UM10800.pdf) for more information.
28  */
30 /* All three UARTs are available, UART numbers are in the range 0 - 2 */
32 #include "core/system.h"
33 #include "core/pio.h"
34 #include "lib/string.h"
35 #include "lib/utils.h"
36 #include "lib/errno.h"
37 #include "drivers/serial.h"
40 struct uart_device
41 {
42         struct lpc_usart* regs;
43         uint32_t baudrate;
44         uint32_t config;
45         uint8_t num;
46         uint8_t capabilities;
47         uint8_t current_mode;
49         /* Output buffer */
50         volatile uint8_t out_buff[SERIAL_OUT_BUFF_SIZE];
51         volatile uint32_t sending; /* Actual sending position in out buffer */
52         /* This lock only prevents multiple calls to serial_write() to execute simultaneously */
53         volatile uint32_t out_lock;
54         volatile uint32_t out_length; /* actual position to add in out buffer */
56         /* Input */
57         void (*rx_callback)(uint8_t); /* Possible RX callback */
58 };
60 #define NUM_UARTS 3
61 static struct uart_device uarts[NUM_UARTS] = {
62         {
63                 .num = 0,
64                 .regs = (struct lpc_usart*)LPC_UART_0,
65                 .baudrate = 0,
66                 .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
67                 .out_buff = {0},
68                 .sending = 0,
69                 .out_lock = 0,
70                 .rx_callback = NULL,
71                 .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
72                 .current_mode = SERIAL_MODE_UART,
73         },
74         {
75                 .num = 1,
76                 .regs = (struct lpc_usart*)LPC_UART_1,
77                 .baudrate = 0,
78                 .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
79                 .out_buff = {0},
80                 .sending = 0,
81                 .out_lock = 0,
82                 .rx_callback = NULL,
83                 .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
84                 .current_mode = SERIAL_MODE_UART,
85         },
86         {
87                 .num = 2,
88                 .regs = (struct lpc_usart*)LPC_UART_2,
89                 .baudrate = 0,
90                 .config = (LPC_UART_8BIT | LPC_UART_NO_PAR | LPC_UART_1STOP),
91                 .out_buff = {0},
92                 .sending = 0,
93                 .out_lock = 0,
94                 .rx_callback = NULL,
95                 .capabilities = (SERIAL_CAP_UART | SERIAL_CAP_RS485),
96                 .current_mode = SERIAL_MODE_UART,
97         },
98 };
100 static void uart_check_rx(struct uart_device* uart, uint32_t intr)
102         if (intr & LPC_UART_ST_RX_READY) {
103                 uint8_t data = uart->regs->rx_data;
104                 if (uart->rx_callback != NULL) {
105                         /* Call the Rx callback */
106                         uart->rx_callback(data);
107                 } else {
108                         /* Echo ? */
109                         if (!uart->sending) {
110                                 uart->regs->tx_data = data;
111                         }
112                 }
113         }
114         /* FIXME : handle RX erors */
117 static void uart_check_tx(struct uart_device* uart, uint32_t intr)
119         /* We are currently sending, send next char */
120         if (intr & LPC_UART_ST_TX_READY) {
121                 if (uart->sending && (uart->out_length > uart->sending)) {
122                         uart->regs->tx_data = uart->out_buff[uart->sending++];
123                 } else {
124                         uart->sending = 0;
125                         uart->regs->inten_clear = LPC_UART_ST_TX_READY;
126                 }
127         }
130 /* Generic UART handler */
131 static void UART_Handler(struct uart_device* uart)
133         uint32_t intr = uart->regs->status;
135         uart_check_rx(uart, intr);
136         uart_check_tx(uart, intr);
137         /* Clear all flags */
138         uart->regs->status = LPC_UART_ST_CLEAR;
142 /* Handlers */
143 void UART_0_Handler(void)
145         UART_Handler(&uarts[0]);
147 void UART_1_Handler(void)
149         UART_Handler(&uarts[1]);
151 void UART_2_Handler(void)
153         UART_Handler(&uarts[2]);
157 /* Start sending buffer content */
158 static void uart_start_sending(uint32_t uart_num)
160         struct uart_device* uart = &uarts[uart_num];
162         if (!uart->sending && (uart->out_length != 0)) {
163                 uart->sending++;
164                 uart->regs->tx_data = uart->out_buff[0];
165                 /* Activate only LPC_UART_ST_TX_READY in order to prevent multiple calls to
166                  * the interrupt handler, which will cause data loss */
167                 uart->regs->inten_set = (LPC_UART_ST_TX_READY);
168         }
172 /****************************************************************************** */
173 /*    Serial send byte - quick function with almost no tests.
174  * If the uart is not sending, the byte is placed directly in the data buffer and
175  * the call returns 0.
176  * Else, the call returns -EBUSY and nothing is sent.
177  */
178 int serial_send_quickbyte(uint32_t uart_num, uint8_t data)
180         struct uart_device* uart = &uarts[uart_num];
181         if (!uart->sending) {
182                 uart->regs->tx_data = data;
183                 return 0;
184         } else {
185                 return -EBUSY;
186         }
189 /***************************************************************************** */
190 /*    Serial Write
191  *
192  * Try to send at most "length" characters from "buf" on the requested uart.
193  * Returns a negative value on error, or number of characters copied into output buffer,
194  * witch may be less than requested "length"
195  * Possible errors: requested uart does not exists (-EINVAL) or unable to acquire uart
196  * lock (-EBUSY).
197  *
198  * Warning for Real Time : This implementation will block if there's already a
199  * transmission ongoing.
200  */
201 int serial_write(uint32_t uart_num, const char *buf, uint32_t length)
203         struct uart_device* uart = NULL;
205         if (uart_num >= NUM_UARTS)
206                 return -EINVAL;
208         uart = &uarts[uart_num];
209         /* Lock acquire */
210         if (sync_lock_test_and_set(&uart->out_lock, 1) == 1) {
211                 return -EBUSY;
212         }
214         /* If UART is sending wait for buffer empty */
215         /* FIXME : be smart for OS, call scheduler or return */
216         while (uart->sending != 0) {
217                 /* If interrupt are masked, check for tx ourselves */
218                 if (get_priority_mask() != 0) {
219                         uart_check_tx(uart, uart->regs->status);
220                 }
221         }
223         if (length > SERIAL_OUT_BUFF_SIZE) {
224                 length = SERIAL_OUT_BUFF_SIZE;
225         }
226         memcpy((void*)uart->out_buff, buf, length);
227         uart->out_length = length;
229         /* Turn output on */
230         uart_start_sending(uart_num);
232         /* Release the lock */
233         sync_lock_release(&uart->out_lock);
235         return length;
239 /***************************************************************************** */
240 /*    Serial Flush
241  *
242  * Wait until all characters have been sent
243  * Returns -EINVAL on error, 0 on success.
244  * Possible errors: requested uart does not exists or unable to acquire uart lock.
245  *
246  * Warning for Real Time : This implementation will block if there's already a
247  * transmission ongoing.
248  */
249 int serial_flush(uint32_t uart_num)
251         struct uart_device* uart = NULL;
253         if (uart_num >= NUM_UARTS)
254                 return -EINVAL;
256         uart = &uarts[uart_num];
258         /* Active wait for message to be sent. If interrupts are
259          * disabled, call the UART handler while waiting. */
260         while (uart->sending) {
261                 if (get_priority_mask() == 0) {
262                         uart_check_tx(uart, uart->regs->status);
263                 }
264         }
266         return 0;
270 /***************************************************************************** */
271 /*   UART Setup : private part : Clocks, Pins, Power and Mode   */
273 /* UART Clock Setup */
274 /* Note : for all uarts we use full peripheral clock.
275  * The common uart clock is the main_clock divided by UARTCLKDIV (which we set to 1)
276  * The uart pclk (U_PCLK) is common uart clock divided by (1 + mult/div)
277  *   - Documentation states that div must be 256 (uart_common_fclk_div = 0xFF)
278  *   - In order to get the closest value for 115200 bauds, the mult value is 22, which
279  *     provides a 11050360 Hz clock with a 12Mhz system clock (ideal value would be
280  *     11059200 Hz). Then the uart specific baud rate generator divisor can be set to 6
281  *     (BRGVAL = 5) in order to get the 1843200 Hz clock which is 16x the 115200 baud
282  *     rate (oversampling of 16).
283  *     Depending on the main clock frequency, other values can be achieved by selecting
284  *     the right baud rate generator divisor (BRGVAL).
285  *   - In order to get the closest value for 1500000 bauds (1.5Mbauds) the mult value
286 *      should be 128 and the main clock set to 36MHz, which gives a 24MHz uart pclk.
287  *     A baud rate generator divisor of 1 (BRGVAL = 0) would then provide a 1.5MHz baudrate
288  *     with 16x oversampling.
289  */
290 enum uart_speed_types {
291         LPC_UART_CLK_NONE,
292         LPC_UART_CLK_COMMON,
293         LPC_UART_CLK_HIGH_SPEED,
294 };
295 static uint8_t uart_speed_type = LPC_UART_CLK_NONE;
296 static int uart_clk_on(uint32_t uart_num, uint32_t baudrate)
298         struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
299         struct lpc_usart* uart_regs = uarts[uart_num].regs; /* Get the right registers */
300         uint32_t div = 0;
301         /* clk_mult is the 12MHz multiplier which gives the main clock freq */
302         uint8_t clk_mult = (get_main_clock() / (12 * 1000 * 1000));
304         /* Save baudrate value */
305         uarts[uart_num].baudrate = baudrate;
307         /* Configure common UART clock */
308         sys_config->uart_clk_div = 0x01; /* Do not divide peripheral clock for uarts */
309         sys_config->uart_common_fclk_div = 0xFF; /* divider value must be 256 */
310         if (baudrate <= 230400) {
311                 if (uart_speed_type == LPC_UART_CLK_HIGH_SPEED) {
312                         return -1;
313                 }
314                 sys_config->uart_common_fclk_mult = 22; /* Closest value to get 115200 baudrate */
315                 /* Get the divider value */
316                 div = (691200 * clk_mult) / baudrate; /* 691200 is (11059200 / 16) */
317                 uart_regs->baudrate_gen = (div - 1);
318                 uart_speed_type = LPC_UART_CLK_COMMON;
319         } else {
320                 if (uart_speed_type == LPC_UART_CLK_COMMON) {
321                         return -EINVAL;
322                 }
323                 sys_config->uart_common_fclk_mult = 128; /* Value to get 1500000 baudrate */
324                 uart_speed_type = LPC_UART_CLK_HIGH_SPEED;
325                 uart_regs->baudrate_gen = 0;
326         }
327         return 0;
329 static void uart_clk_off(uint32_t uart_num)
331         /* Erase saved baudrate */
332         uarts[uart_num].baudrate = 0;
335 static void uart_setup(uint32_t uart_num)
337         struct lpc_usart* uart_regs = uarts[uart_num].regs; /* Get the right registers */
338         /* Set up UART mode */
339         uart_regs->config = (uarts[uart_num].config | LPC_UART_ENABLE);
340         uart_regs->control = 0;
341         /* Clear the Status Register */
342         uart_regs->status = LPC_UART_ST_CLEAR;
343         /* Enable UART Interrupt */
344         uart_regs->inten_set = LPC_UART_ST_RX_READY;
347 /* Change UART configuration (number of data, parity and stop bits).
348  * config is usually a mask of LPC_UART_xBIT (x = 5..8), LPC_UART_xSTOP (x = 1..2)
349  *   and one of LPC_UART_NO_PAR, LPC_UART_ODD_PAR or LPC_UART_EVEN_PAR.
350  */
351 int uart_set_config(uint8_t uart_num, uint32_t config)
353         struct uart_device* uart = NULL;
355         if (uart_num >= NUM_UARTS)
356                 return -EINVAL;
357         uart = &uarts[uart_num];
358         uart->config = config;
359         return 0;
362 struct uart_def
364         uint32_t irq;
365         uint32_t power_offset;
366 };
367 static struct uart_def uart_defs[NUM_UARTS] = {
368         { UART0_IRQ, LPC_SYS_ABH_CLK_CTRL_UART0 },
369         { UART1_IRQ, LPC_SYS_ABH_CLK_CTRL_UART1 },
370         { UART2_IRQ, LPC_SYS_ABH_CLK_CTRL_UART2 },
371 };
373 /***************************************************************************** */
374 /*   Public access to UART setup   */
376 /* Allow any change to the main clock to be forwarded to us */
377 void uart_clk_update(void)
379         int i = 0;
380         for (i = 0; i < NUM_UARTS; i++) {
381                 if (uarts[i].baudrate != 0) {
382                         uart_clk_on(i, uarts[i].baudrate);
383                 }
384         }
387 /* Change uart mode to RS485
388  * return -ENODEV when the device does not support RS485 mode.
389  */
390 int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay)
392         struct uart_device* uart = NULL;
393         struct lpc_usart* uart_regs = NULL;
394         if (uart_num >= NUM_UARTS)
395                 return -EINVAL;
396         uart = &uarts[uart_num];
397         uart_regs = uart->regs; /* Get the right registers */
399         if (!(uart->capabilities & SERIAL_CAP_RS485)) {
400                 return -ENODEV;
401         }
403         /* Set current mode */
404         uart->current_mode = SERIAL_MODE_RS485;
405         uart_regs->config = 0; /* FIXME */
406         uart_regs->control = 0; /* FIXME */
407         uart_regs->address = LPC_RS485_ADDR(addr);
408         return 0;
412 /* Do we need to allow setting of other parameters ? (Other than 8n1) */
413 int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t))
415         struct uart_def* uartdef = NULL;
416         uint32_t status = 0;
418         if (uart_num >= NUM_UARTS)
419                 return -EINVAL;
420         uartdef = &uart_defs[uart_num];
421         uarts[uart_num].rx_callback = rx_callback;
423         NVIC_DisableIRQ( uartdef->irq );
424         /* Turn On power */
425         subsystem_power(uartdef->power_offset, 1);
426         /* Setup clock acording to baudrate */
427         status = uart_clk_on(uart_num, baudrate);
428         /* Setup */
429         uart_setup(uart_num);
430         /* Enable interrupts back on */
431         NVIC_EnableIRQ( uartdef->irq );
433         return status;
436 void uart_off(uint32_t uart_num)
438         struct uart_def* uartdef = NULL;
439         if (uart_num >= NUM_UARTS)
440                 return;
441         uartdef = &uart_defs[uart_num];
443         NVIC_DisableIRQ( uartdef->irq );
444         uart_clk_off(uart_num);
445         /* Turn Off power */
446         subsystem_power(uartdef->power_offset, 0);
447         uarts[uart_num].rx_callback = NULL;
448         uarts[uart_num].regs->config = 0;