Changes to ADC API
[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 char 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                         uart->regs->tx_data = data;
110                 }
111         }
112         /* FIXME : handle RX erors */
115 static void uart_check_tx(struct uart_device* uart, uint32_t intr)
117         /* We are currently sending, send next char */
118         if (intr & LPC_UART_ST_TX_READY) {
119                 if (uart->out_buff && uart->sending && (uart->out_length > uart->sending)) {
120                         uart->regs->tx_data = uart->out_buff[uart->sending];
121                         uart->sending++;
122                 } else {
123                         uart->sending = 0;
124                         uart->regs->inten_clear = LPC_UART_ST_TX_READY;
125                 }
126         }
129 /* Generic UART handler */
130 static void UART_Handler(struct uart_device* uart)
132         uint32_t intr = uart->regs->status;
134         uart_check_rx(uart, intr);
135         uart_check_tx(uart, intr);
136         /* Clear all flags */
137         uart->regs->status = LPC_UART_ST_CLEAR;
141 /* Handlers */
142 void UART_0_Handler(void)
144         UART_Handler(&uarts[0]);
146 void UART_1_Handler(void)
148         UART_Handler(&uarts[1]);
150 void UART_2_Handler(void)
152         UART_Handler(&uarts[2]);
156 /* Start sending buffer content */
157 static void uart_start_sending(uint32_t uart_num)
159         struct uart_device* uart = &uarts[uart_num];
161         if (!uart->sending && (uart->out_length != 0)) {
162                 uart->sending++;
163                 uart->regs->tx_data = uart->out_buff[0];
164                 /* Activate only LPC_UART_ST_TX_READY in order to prevent multiple calls to
165                  * the interrupt handler, which will cause data loss */
166                 uart->regs->inten_set = (LPC_UART_ST_TX_READY);
167         }
171 /****************************************************************************** */
172 /*    Serial send byte - quick function with almost no tests.
173  * If the uart is not sending, the byte is placed directly in the data buffer and
174  * the call returns 0.
175  * Else, the call returns -EBUSY and nothing is sent.
176  */
177 int serial_send_quickbyte(uint32_t uart_num, uint8_t data)
179         struct uart_device* uart = &uarts[uart_num];
180         if (!uart->sending) {
181                 uart->regs->tx_data = data;
182                 return 0;
183         } else {
184                 return -EBUSY;
185         }
188 /***************************************************************************** */
189 /*    Serial Write
190  *
191  * Try to send at most "length" characters from "buf" on the requested uart.
192  * Returns a negative value on error, or number of characters copied into output buffer,
193  * witch may be less than requested "length"
194  * Possible errors: requested uart does not exists (-EINVAL) or unable to acquire uart
195  * lock (-EBUSY).
196  *
197  * Warning for Real Time : This implementation will block if there's already a
198  * transmission ongoing.
199  */
200 int serial_write(uint32_t uart_num, const char *buf, uint32_t length)
202         struct uart_device* uart = NULL;
204         if (uart_num >= NUM_UARTS)
205                 return -EINVAL;
207         uart = &uarts[uart_num];
208         /* Lock acquire */
209         if (sync_lock_test_and_set(&uart->out_lock, 1) == 1) {
210                 return -EBUSY;
211         }
213         /* If UART is sending wait for buffer empty */
214         /* FIXME : be smart for OS, call scheduler or return */
215         while (uart->sending != 0) {
216                 /* If interrupt are masked, check for tx ourselves */
217                 if (get_priority_mask() != 0) {
218                         uart_check_tx(uart, uart->regs->status);
219                 }
220         }
222         if (length > SERIAL_OUT_BUFF_SIZE) {
223                 length = SERIAL_OUT_BUFF_SIZE;
224         }
225         memcpy((char*)uart->out_buff, buf, length);
226         uart->out_length = length;
228         /* Turn output on */
229         uart_start_sending(uart_num);
231         /* Release the lock */
232         sync_lock_release(&uart->out_lock);
234         return length;
238 /***************************************************************************** */
239 /*    Serial Flush
240  *
241  * Wait until all characters have been sent
242  * Returns -EINVAL on error, 0 on success.
243  * Possible errors: requested uart does not exists or unable to acquire uart lock.
244  *
245  * Warning for Real Time : This implementation will block if there's already a
246  * transmission ongoing.
247  */
248 int serial_flush(uint32_t uart_num)
250         struct uart_device* uart = NULL;
252         if (uart_num >= NUM_UARTS)
253                 return -EINVAL;
255         uart = &uarts[uart_num];
257         /* Active wait for message to be sent. If interrupts are
258          * disabled, call the UART handler while waiting. */
259         while (uart->sending) {
260                 if (get_priority_mask() == 0) {
261                         uart_check_tx(uart, uart->regs->status);
262                 }
263         }
265         return 0;
269 /***************************************************************************** */
270 /*   UART Setup : private part : Clocks, Pins, Power and Mode   */
272 /* UART Clock Setup */
273 /* Note : for all uarts we use full peripheral clock.
274  * The common uart clock is the main_clock divided by UARTCLKDIV (which we set to 1)
275  * The uart pclk (U_PCLK) is common uart clock divided by (1 + mult/div)
276  *   - Documentation states that div must be 256 (uart_common_fclk_div = 0xFF)
277  *   - In order to get the closest value for 115200 bauds, the mult value is 22, which
278  *     provides a 11050360 Hz clock with a 12Mhz system clock (ideal value would be
279  *     11059200 Hz). Then the uart specific baud rate generator divisor can be set to 6
280  *     (BRGVAL = 5) in order to get the 1843200 Hz clock which is 16x the 115200 baud
281  *     rate (oversampling of 16).
282  *     Depending on the main clock frequency, other values can be achieved by selecting
283  *     the right baud rate generator divisor (BRGVAL).
284  *   - In order to get the closest value for 1500000 bauds (1.5Mbauds) the mult value
285 *      should be 128 and the main clock set to 36MHz, which gives a 24MHz uart pclk.
286  *     A baud rate generator divisor of 1 (BRGVAL = 0) would then provide a 1.5MHz baudrate
287  *     with 16x oversampling.
288  */
289 enum uart_speed_types {
290         LPC_UART_CLK_NONE,
291         LPC_UART_CLK_COMMON,
292         LPC_UART_CLK_HIGH_SPEED,
293 };
294 static uint8_t uart_speed_type = LPC_UART_CLK_NONE;
295 static int uart_clk_on(uint32_t uart_num, uint32_t baudrate)
297         struct lpc_sys_config* sys_config = LPC_SYS_CONFIG;
298         struct lpc_usart* uart_regs = uarts[uart_num].regs; /* Get the right registers */
299         uint32_t div = 0;
300         /* clk_mult is the 12MHz multiplier which gives the main clock freq */
301         uint8_t clk_mult = (get_main_clock() / (12 * 1000 * 1000));
303         /* Save baudrate value */
304         uarts[uart_num].baudrate = baudrate;
306         /* Configure common UART clock */
307         sys_config->uart_clk_div = 0x01; /* Do not divide peripheral clock for uarts */
308         sys_config->uart_common_fclk_div = 0xFF; /* divider value must be 256 */
309         if (baudrate <= 230400) {
310                 if (uart_speed_type == LPC_UART_CLK_HIGH_SPEED) {
311                         return -1;
312                 }
313                 sys_config->uart_common_fclk_mult = 22; /* Closest value to get 115200 baudrate */
314                 /* Get the divider value */
315                 div = (691200 * clk_mult) / baudrate; /* 691200 is (11059200 / 16) */
316                 uart_regs->baudrate_gen = (div - 1);
317                 uart_speed_type = LPC_UART_CLK_COMMON;
318         } else {
319                 if (uart_speed_type == LPC_UART_CLK_COMMON) {
320                         return -EINVAL;
321                 }
322                 sys_config->uart_common_fclk_mult = 128; /* Value to get 1500000 baudrate */
323                 uart_speed_type = LPC_UART_CLK_HIGH_SPEED;
324                 uart_regs->baudrate_gen = 0;
325         }
326         return 0;
328 static void uart_clk_off(uint32_t uart_num)
330         /* Erase saved baudrate */
331         uarts[uart_num].baudrate = 0;
334 static void uart_setup(uint32_t uart_num)
336         struct lpc_usart* uart_regs = uarts[uart_num].regs; /* Get the right registers */
337         /* Set up UART mode */
338         uart_regs->config = (uarts[uart_num].config | LPC_UART_ENABLE);
339         uart_regs->control = 0;
340         /* Clear the Status Register */
341         uart_regs->status = LPC_UART_ST_CLEAR;
342         /* Enable UART Interrupt */
343         uart_regs->inten_set = LPC_UART_ST_RX_READY;
346 /* Change UART configuration (number of data, parity and stop bits).
347  * config is usually a mask of LPC_UART_xBIT (x = 5..8), LPC_UART_xSTOP (x = 1..2)
348  *   and one of LPC_UART_NO_PAR, LPC_UART_ODD_PAR or LPC_UART_EVEN_PAR.
349  */
350 int uart_set_config(uint8_t uart_num, uint32_t config)
352         struct uart_device* uart = NULL;
354         if (uart_num >= NUM_UARTS)
355                 return -EINVAL;
356         uart = &uarts[uart_num];
357         uart->config = config;
358         return 0;
361 struct uart_def
363         uint32_t irq;
364         uint32_t power_offset;
365 };
366 static struct uart_def uart_defs[NUM_UARTS] = {
367         { UART0_IRQ, LPC_SYS_ABH_CLK_CTRL_UART0 },
368         { UART1_IRQ, LPC_SYS_ABH_CLK_CTRL_UART1 },
369         { UART2_IRQ, LPC_SYS_ABH_CLK_CTRL_UART2 },
370 };
372 /***************************************************************************** */
373 /*   Public access to UART setup   */
375 /* Allow any change to the main clock to be forwarded to us */
376 void uart_clk_update(void)
378         int i = 0;
379         for (i = 0; i < NUM_UARTS; i++) {
380                 if (uarts[i].baudrate != 0) {
381                         uart_clk_on(i, uarts[i].baudrate);
382                 }
383         }
386 /* Change uart mode to RS485
387  * return -ENODEV when the device does not support RS485 mode.
388  */
389 int uart_set_mode_rs485(uint32_t uart_num, uint32_t control, uint8_t addr, uint8_t delay)
391         struct uart_device* uart = NULL;
392         struct lpc_usart* uart_regs = NULL;
393         if (uart_num >= NUM_UARTS)
394                 return -EINVAL;
395         uart = &uarts[uart_num];
396         uart_regs = uart->regs; /* Get the right registers */
398         if (!(uart->capabilities & SERIAL_CAP_RS485)) {
399                 return -ENODEV;
400         }
402         /* Set current mode */
403         uart->current_mode = SERIAL_MODE_RS485;
404         uart_regs->config = 0; /* FIXME */
405         uart_regs->control = 0; /* FIXME */
406         uart_regs->address = LPC_RS485_ADDR(addr);
407         return 0;
411 /* Do we need to allow setting of other parameters ? (Other than 8n1) */
412 int uart_on(uint32_t uart_num, uint32_t baudrate, void (*rx_callback)(uint8_t))
414         struct uart_def* uartdef = NULL;
415         uint32_t status = 0;
417         if (uart_num >= NUM_UARTS)
418                 return -EINVAL;
419         uartdef = &uart_defs[uart_num];
420         uarts[uart_num].rx_callback = rx_callback;
422         NVIC_DisableIRQ( uartdef->irq );
423         /* Turn On power */
424         subsystem_power(uartdef->power_offset, 1);
425         /* Setup clock acording to baudrate */
426         status = uart_clk_on(uart_num, baudrate);
427         /* Setup */
428         uart_setup(uart_num);
429         /* Enable interrupts back on */
430         NVIC_EnableIRQ( uartdef->irq );
432         return status;
435 void uart_off(uint32_t uart_num)
437         struct uart_def* uartdef = NULL;
438         if (uart_num >= NUM_UARTS)
439                 return;
440         uartdef = &uart_defs[uart_num];
442         NVIC_DisableIRQ( uartdef->irq );
443         uart_clk_off(uart_num);
444         /* Turn Off power */
445         subsystem_power(uartdef->power_offset, 0);
446         uarts[uart_num].rx_callback = NULL;
447         uarts[uart_num].regs->config = 0;