1 /* stellarisUartDrv.c - Stellaris UART driver */
2
3 #define DT_DRV_COMPAT ti_stellaris_uart
4
5 /*
6 * Copyright (c) 2013-2015 Wind River Systems, Inc.
7 *
8 * SPDX-License-Identifier: Apache-2.0
9 */
10
11 /**
12 * @brief Driver for Stellaris UART
13 *
14 * Driver for Stellaris UART found namely on TI LM3S6965 board. It is similar to
15 * an 16550 in functionality, but is not register-compatible.
16 * It is also register-compatible with the UART found on TI CC2650 SoC,
17 * so it can be used for boards using it, like the TI SensorTag.
18 *
19 * There is only support for poll-mode, so it can only be used with the printk
20 * and STDOUT_CONSOLE APIs.
21 */
22
23 #include <zephyr/kernel.h>
24 #include <zephyr/arch/cpu.h>
25 #include <zephyr/sys/__assert.h>
26 #include <soc.h>
27 #include <zephyr/init.h>
28 #include <zephyr/drivers/uart.h>
29 #include <zephyr/linker/sections.h>
30 #include <zephyr/irq.h>
31
32 /* definitions */
33
34 /* Stellaris UART module */
35 struct _uart {
36 uint32_t dr;
37 union {
38 uint32_t _sr;
39 uint32_t _cr;
40 } u1;
41 uint8_t _res1[0x010];
42 uint32_t fr;
43 uint8_t _res2[0x04];
44 uint32_t ilpr;
45 uint32_t ibrd;
46 uint32_t fbrd;
47 uint32_t lcrh;
48 uint32_t ctl;
49 uint32_t ifls;
50 uint32_t im;
51 uint32_t ris;
52 uint32_t mis;
53 uint32_t icr;
54 uint8_t _res3[0xf8c];
55
56 uint32_t peripd_id4;
57 uint32_t peripd_id5;
58 uint32_t peripd_id6;
59 uint32_t peripd_id7;
60 uint32_t peripd_id0;
61 uint32_t peripd_id1;
62 uint32_t peripd_id2;
63 uint32_t peripd_id3;
64
65 uint32_t p_cell_id0;
66 uint32_t p_cell_id1;
67 uint32_t p_cell_id2;
68 uint32_t p_cell_id3;
69 };
70
71 struct uart_stellaris_config {
72 volatile struct _uart *uart;
73 uint32_t sys_clk_freq;
74 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
75 uart_irq_config_func_t irq_config_func;
76 #endif
77 };
78
79 /* Device data structure */
80 struct uart_stellaris_dev_data_t {
81 uint32_t baud_rate; /* Baud rate */
82
83 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
84 uart_irq_callback_user_data_t cb; /**< Callback function pointer */
85 void *cb_data; /**< Callback function arg */
86 #endif
87 };
88
89 /* bits */
90 #define UARTFR_BUSY 0x00000008
91 #define UARTFR_RXFE 0x00000010
92 #define UARTFR_TXFF 0x00000020
93 #define UARTFR_RXFF 0x00000040
94 #define UARTFR_TXFE 0x00000080
95
96 #define UARTLCRH_FEN 0x00000010
97 #define UARTLCRH_WLEN 0x00000060
98
99 #define UARTCTL_UARTEN 0x00000001
100 #define UARTCTL_LBE 0x00000800
101 #define UARTCTL_TXEN 0x00000100
102 #define UARTCTL_RXEN 0x00000200
103
104 #define UARTTIM_RXIM 0x00000010
105 #define UARTTIM_TXIM 0x00000020
106 #define UARTTIM_RTIM 0x00000040
107 #define UARTTIM_FEIM 0x00000080
108 #define UARTTIM_PEIM 0x00000100
109 #define UARTTIM_BEIM 0x00000200
110 #define UARTTIM_OEIM 0x00000400
111
112 #define UARTMIS_RXMIS 0x00000010
113 #define UARTMIS_TXMIS 0x00000020
114
115 static const struct uart_driver_api uart_stellaris_driver_api;
116
117 /**
118 * @brief Set the baud rate
119 *
120 * This routine set the given baud rate for the UART.
121 *
122 * @param dev UART device struct
123 * @param baudrate Baud rate
124 * @param sys_clk_freq_hz System clock frequency in Hz
125 */
baudrate_set(const struct device * dev,uint32_t baudrate,uint32_t sys_clk_freq_hz)126 static void baudrate_set(const struct device *dev,
127 uint32_t baudrate, uint32_t sys_clk_freq_hz)
128 {
129 const struct uart_stellaris_config *config = dev->config;
130 uint32_t brdi, brdf, div, rem;
131
132 /* upon reset, the system clock uses the internal OSC @ 12MHz */
133
134 div = (baudrate * 16U);
135 rem = sys_clk_freq_hz % div;
136
137 /*
138 * floating part of baud rate (LM3S6965 p.433), equivalent to
139 * [float part of (SYSCLK / div)] * 64 + 0.5
140 */
141 brdf = ((((rem * 64U) << 1) / div) + 1) >> 1;
142
143 /* integer part of baud rate (LM3S6965 p.433) */
144 brdi = sys_clk_freq_hz / div;
145
146 /*
147 * those registers are 32-bit, but the reserved bits should be
148 * preserved
149 */
150 config->uart->ibrd = (uint16_t)(brdi & 0xffff); /* 16 bits */
151 config->uart->fbrd = (uint8_t)(brdf & 0x3f); /* 6 bits */
152 }
153
154 /**
155 * @brief Enable the UART
156 *
157 * This routine enables the given UART.
158 *
159 * @param dev UART device struct
160 */
enable(const struct device * dev)161 static inline void enable(const struct device *dev)
162 {
163 const struct uart_stellaris_config *config = dev->config;
164
165 config->uart->ctl |= UARTCTL_UARTEN;
166 }
167
168 /**
169 * @brief Disable the UART
170 *
171 * This routine disables the given UART.
172 *
173 * @param dev UART device struct
174 */
disable(const struct device * dev)175 static inline void disable(const struct device *dev)
176 {
177 const struct uart_stellaris_config *config = dev->config;
178
179 config->uart->ctl &= ~UARTCTL_UARTEN;
180
181 /* ensure transmissions are complete */
182 while (config->uart->fr & UARTFR_BUSY) {
183 }
184
185 /* flush the FIFOs by disabling them */
186 config->uart->lcrh &= ~UARTLCRH_FEN;
187 }
188
189 /*
190 * no stick parity
191 * 8-bit frame
192 * FIFOs disabled
193 * one stop bit
194 * parity disabled
195 * send break off
196 */
197 #define LINE_CONTROL_DEFAULTS UARTLCRH_WLEN
198
199 /**
200 * @brief Set the default UART line controls
201 *
202 * This routine sets the given UART's line controls to their default settings.
203 *
204 * @param dev UART device struct
205 */
line_control_defaults_set(const struct device * dev)206 static inline void line_control_defaults_set(const struct device *dev)
207 {
208 const struct uart_stellaris_config *config = dev->config;
209
210 config->uart->lcrh = LINE_CONTROL_DEFAULTS;
211 }
212
213 /**
214 * @brief Initialize UART channel
215 *
216 * This routine is called to reset the chip in a quiescent state.
217 * It is assumed that this function is called only once per UART.
218 *
219 * @param dev UART device struct
220 *
221 * @return 0
222 */
uart_stellaris_init(const struct device * dev)223 static int uart_stellaris_init(const struct device *dev)
224 {
225 struct uart_stellaris_dev_data_t *data = dev->data;
226 const struct uart_stellaris_config *config = dev->config;
227 disable(dev);
228 baudrate_set(dev, data->baud_rate,
229 config->sys_clk_freq);
230 line_control_defaults_set(dev);
231 enable(dev);
232
233 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
234 config->irq_config_func(dev);
235 #endif
236
237 return 0;
238 }
239
240 /**
241 * @brief Get the UART transmit ready status
242 *
243 * This routine returns the given UART's transmit ready status.
244 *
245 * @param dev UART device struct
246 *
247 * @return 0 if ready to transmit, 1 otherwise
248 */
poll_tx_ready(const struct device * dev)249 static int poll_tx_ready(const struct device *dev)
250 {
251 const struct uart_stellaris_config *config = dev->config;
252
253 return (config->uart->fr & UARTFR_TXFE);
254 }
255
256 /**
257 * @brief Poll the device for input.
258 *
259 * @param dev UART device struct
260 * @param c Pointer to character
261 *
262 * @return 0 if a character arrived, -1 if the input buffer if empty.
263 */
264
uart_stellaris_poll_in(const struct device * dev,unsigned char * c)265 static int uart_stellaris_poll_in(const struct device *dev, unsigned char *c)
266 {
267 const struct uart_stellaris_config *config = dev->config;
268
269 if (config->uart->fr & UARTFR_RXFE) {
270 return (-1);
271 }
272
273 /* got a character */
274 *c = (unsigned char)config->uart->dr;
275
276 return 0;
277 }
278
279 /**
280 * @brief Output a character in polled mode.
281 *
282 * Checks if the transmitter is empty. If empty, a character is written to
283 * the data register.
284 *
285 * @param dev UART device struct
286 * @param c Character to send
287 */
uart_stellaris_poll_out(const struct device * dev,unsigned char c)288 static void uart_stellaris_poll_out(const struct device *dev,
289 unsigned char c)
290 {
291 const struct uart_stellaris_config *config = dev->config;
292
293 while (!poll_tx_ready(dev)) {
294 }
295
296 /* send a character */
297 config->uart->dr = (uint32_t)c;
298 }
299
300 #if CONFIG_UART_INTERRUPT_DRIVEN
301
302 /**
303 * @brief Fill FIFO with data
304 *
305 * @param dev UART device struct
306 * @param tx_data Data to transmit
307 * @param len Number of bytes to send
308 *
309 * @return Number of bytes sent
310 */
uart_stellaris_fifo_fill(const struct device * dev,const uint8_t * tx_data,int len)311 static int uart_stellaris_fifo_fill(const struct device *dev,
312 const uint8_t *tx_data,
313 int len)
314 {
315 const struct uart_stellaris_config *config = dev->config;
316 uint8_t num_tx = 0U;
317
318 while ((len - num_tx > 0) && ((config->uart->fr & UARTFR_TXFF) == 0U)) {
319 config->uart->dr = (uint32_t)tx_data[num_tx++];
320 }
321
322 return (int)num_tx;
323 }
324
325 /**
326 * @brief Read data from FIFO
327 *
328 * @param dev UART device struct
329 * @param rx_data Pointer to data container
330 * @param size Container size
331 *
332 * @return Number of bytes read
333 */
uart_stellaris_fifo_read(const struct device * dev,uint8_t * rx_data,const int size)334 static int uart_stellaris_fifo_read(const struct device *dev,
335 uint8_t *rx_data,
336 const int size)
337 {
338 const struct uart_stellaris_config *config = dev->config;
339 uint8_t num_rx = 0U;
340
341 while ((size - num_rx > 0) && ((config->uart->fr & UARTFR_RXFE) == 0U)) {
342 rx_data[num_rx++] = (uint8_t)config->uart->dr;
343 }
344
345 return num_rx;
346 }
347
348 /**
349 * @brief Enable TX interrupt
350 *
351 * @param dev UART device struct
352 */
uart_stellaris_irq_tx_enable(const struct device * dev)353 static void uart_stellaris_irq_tx_enable(const struct device *dev)
354 {
355 static uint8_t first_time =
356 1U; /* used to allow the first transmission */
357 uint32_t saved_ctl; /* saved UARTCTL (control) register */
358 uint32_t saved_ibrd; /* saved UARTIBRD (integer baud rate) register */
359 uint32_t saved_fbrd; /* saved UARTFBRD (fractional baud rate) register
360 */
361 const struct uart_stellaris_config *config = dev->config;
362
363 if (first_time) {
364 /*
365 * The Tx interrupt will not be set when transmission is first
366 * enabled.
367 * A character has to be transmitted before Tx interrupts will
368 * work,
369 * so send one via loopback mode.
370 */
371 first_time = 0U;
372
373 /* save current control and baud rate settings */
374 saved_ctl = config->uart->ctl;
375 saved_ibrd = config->uart->ibrd;
376 saved_fbrd = config->uart->fbrd;
377
378 /* send a character with default settings via loopback */
379 disable(dev);
380 config->uart->fbrd = 0U;
381 config->uart->ibrd = 1U;
382 config->uart->lcrh = 0U;
383 config->uart->ctl = (UARTCTL_UARTEN | UARTCTL_TXEN | UARTCTL_LBE);
384 config->uart->dr = 0U;
385
386 while (config->uart->fr & UARTFR_BUSY) {
387 }
388
389 /* restore control and baud rate settings */
390 disable(dev);
391 config->uart->ibrd = saved_ibrd;
392 config->uart->fbrd = saved_fbrd;
393 line_control_defaults_set(dev);
394 config->uart->ctl = saved_ctl;
395 }
396
397 config->uart->im |= UARTTIM_TXIM;
398 }
399
400 /**
401 * @brief Disable TX interrupt in IER
402 *
403 * @param dev UART device struct
404 */
uart_stellaris_irq_tx_disable(const struct device * dev)405 static void uart_stellaris_irq_tx_disable(const struct device *dev)
406 {
407 const struct uart_stellaris_config *config = dev->config;
408
409 config->uart->im &= ~UARTTIM_TXIM;
410 }
411
412 /**
413 * @brief Check if Tx IRQ has been raised
414 *
415 * @param dev UART device struct
416 *
417 * @return 1 if a Tx IRQ is pending, 0 otherwise
418 */
uart_stellaris_irq_tx_ready(const struct device * dev)419 static int uart_stellaris_irq_tx_ready(const struct device *dev)
420 {
421 const struct uart_stellaris_config *config = dev->config;
422
423 return ((config->uart->mis & UARTMIS_TXMIS) == UARTMIS_TXMIS);
424 }
425
426 /**
427 * @brief Enable RX interrupt in IER
428 *
429 * @param dev UART device struct
430 */
uart_stellaris_irq_rx_enable(const struct device * dev)431 static void uart_stellaris_irq_rx_enable(const struct device *dev)
432 {
433 const struct uart_stellaris_config *config = dev->config;
434
435 config->uart->im |= UARTTIM_RXIM;
436 }
437
438 /**
439 * @brief Disable RX interrupt in IER
440 *
441 * @param dev UART device struct
442 */
uart_stellaris_irq_rx_disable(const struct device * dev)443 static void uart_stellaris_irq_rx_disable(const struct device *dev)
444 {
445 const struct uart_stellaris_config *config = dev->config;
446
447 config->uart->im &= ~UARTTIM_RXIM;
448 }
449
450 /**
451 * @brief Check if Rx IRQ has been raised
452 *
453 * @param dev UART device struct
454 *
455 * @return 1 if an IRQ is ready, 0 otherwise
456 */
uart_stellaris_irq_rx_ready(const struct device * dev)457 static int uart_stellaris_irq_rx_ready(const struct device *dev)
458 {
459 const struct uart_stellaris_config *config = dev->config;
460
461 return ((config->uart->mis & UARTMIS_RXMIS) == UARTMIS_RXMIS);
462 }
463
464 /**
465 * @brief Enable error interrupts
466 *
467 * @param dev UART device struct
468 */
uart_stellaris_irq_err_enable(const struct device * dev)469 static void uart_stellaris_irq_err_enable(const struct device *dev)
470 {
471 const struct uart_stellaris_config *config = dev->config;
472
473 config->uart->im |= (UARTTIM_RTIM | UARTTIM_FEIM | UARTTIM_PEIM |
474 UARTTIM_BEIM | UARTTIM_OEIM);
475 }
476
477 /**
478 * @brief Disable error interrupts
479 *
480 * @param dev UART device struct
481 */
uart_stellaris_irq_err_disable(const struct device * dev)482 static void uart_stellaris_irq_err_disable(const struct device *dev)
483 {
484 const struct uart_stellaris_config *config = dev->config;
485
486 config->uart->im &= ~(UARTTIM_RTIM | UARTTIM_FEIM | UARTTIM_PEIM |
487 UARTTIM_BEIM | UARTTIM_OEIM);
488 }
489
490 /**
491 * @brief Check if Tx or Rx IRQ is pending
492 *
493 * @param dev UART device struct
494 *
495 * @return 1 if a Tx or Rx IRQ is pending, 0 otherwise
496 */
uart_stellaris_irq_is_pending(const struct device * dev)497 static int uart_stellaris_irq_is_pending(const struct device *dev)
498 {
499 const struct uart_stellaris_config *config = dev->config;
500
501 /* Look only at Tx and Rx data interrupt flags */
502 return ((config->uart->mis & (UARTMIS_RXMIS | UARTMIS_TXMIS)) ? 1 : 0);
503 }
504
505 /**
506 * @brief Update IRQ status
507 *
508 * @param dev UART device struct
509 *
510 * @return Always 1
511 */
uart_stellaris_irq_update(const struct device * dev)512 static int uart_stellaris_irq_update(const struct device *dev)
513 {
514 return 1;
515 }
516
517 /**
518 * @brief Set the callback function pointer for IRQ.
519 *
520 * @param dev UART device struct
521 * @param cb Callback function pointer.
522 */
uart_stellaris_irq_callback_set(const struct device * dev,uart_irq_callback_user_data_t cb,void * cb_data)523 static void uart_stellaris_irq_callback_set(const struct device *dev,
524 uart_irq_callback_user_data_t cb,
525 void *cb_data)
526 {
527 struct uart_stellaris_dev_data_t * const dev_data = dev->data;
528
529 dev_data->cb = cb;
530 dev_data->cb_data = cb_data;
531 }
532
533 /**
534 * @brief Interrupt service routine.
535 *
536 * This simply calls the callback function, if one exists.
537 *
538 * @param arg Argument to ISR.
539 */
uart_stellaris_isr(const struct device * dev)540 static void uart_stellaris_isr(const struct device *dev)
541 {
542 struct uart_stellaris_dev_data_t * const dev_data = dev->data;
543
544 if (dev_data->cb) {
545 dev_data->cb(dev, dev_data->cb_data);
546 }
547 }
548
549 #endif /* CONFIG_UART_INTERRUPT_DRIVEN */
550
551
552 static const struct uart_driver_api uart_stellaris_driver_api = {
553 .poll_in = uart_stellaris_poll_in,
554 .poll_out = uart_stellaris_poll_out,
555
556 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
557
558 .fifo_fill = uart_stellaris_fifo_fill,
559 .fifo_read = uart_stellaris_fifo_read,
560 .irq_tx_enable = uart_stellaris_irq_tx_enable,
561 .irq_tx_disable = uart_stellaris_irq_tx_disable,
562 .irq_tx_ready = uart_stellaris_irq_tx_ready,
563 .irq_rx_enable = uart_stellaris_irq_rx_enable,
564 .irq_rx_disable = uart_stellaris_irq_rx_disable,
565 .irq_rx_ready = uart_stellaris_irq_rx_ready,
566 .irq_err_enable = uart_stellaris_irq_err_enable,
567 .irq_err_disable = uart_stellaris_irq_err_disable,
568 .irq_is_pending = uart_stellaris_irq_is_pending,
569 .irq_update = uart_stellaris_irq_update,
570 .irq_callback_set = uart_stellaris_irq_callback_set,
571
572 #endif
573 };
574
575
576 #ifdef CONFIG_UART_STELLARIS_PORT_0
577
578 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
579 static void irq_config_func_0(const struct device *port);
580 #endif
581
582 static const struct uart_stellaris_config uart_stellaris_dev_cfg_0 = {
583 .uart = (volatile struct _uart *)DT_INST_REG_ADDR(0),
584 .sys_clk_freq = DT_INST_PROP_BY_PHANDLE(0, clocks, clock_frequency),
585
586 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
587 .irq_config_func = irq_config_func_0,
588 #endif
589 };
590
591 static struct uart_stellaris_dev_data_t uart_stellaris_dev_data_0 = {
592 .baud_rate = DT_INST_PROP(0, current_speed),
593 };
594
595 DEVICE_DT_INST_DEFINE(0,
596 uart_stellaris_init,
597 NULL,
598 &uart_stellaris_dev_data_0, &uart_stellaris_dev_cfg_0,
599 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,
600 &uart_stellaris_driver_api);
601
602 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
irq_config_func_0(const struct device * dev)603 static void irq_config_func_0(const struct device *dev)
604 {
605 IRQ_CONNECT(DT_INST_IRQN(0),
606 DT_INST_IRQ(0, priority),
607 uart_stellaris_isr, DEVICE_DT_INST_GET(0),
608 0);
609 irq_enable(DT_INST_IRQN(0));
610 }
611 #endif
612
613 #endif /* CONFIG_UART_STELLARIS_PORT_0 */
614
615 #ifdef CONFIG_UART_STELLARIS_PORT_1
616
617 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
618 static void irq_config_func_1(const struct device *port);
619 #endif
620
621 static struct uart_stellaris_config uart_stellaris_dev_cfg_1 = {
622 .uart = (volatile struct _uart *)DT_INST_REG_ADDR(1),
623 .sys_clk_freq = DT_INST_PROP_BY_PHANDLE(1, clocks, clock_frequency),
624
625 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
626 .irq_config_func = irq_config_func_1,
627 #endif
628 };
629
630 static struct uart_stellaris_dev_data_t uart_stellaris_dev_data_1 = {
631 .baud_rate = DT_INST_PROP(1, current_speed),
632 };
633
634 DEVICE_DT_INST_DEFINE(1,
635 uart_stellaris_init,
636 NULL,
637 &uart_stellaris_dev_data_1, &uart_stellaris_dev_cfg_1,
638 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,
639 &uart_stellaris_driver_api);
640
641 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
irq_config_func_1(const struct device * dev)642 static void irq_config_func_1(const struct device *dev)
643 {
644 IRQ_CONNECT(DT_INST_IRQN(1),
645 DT_INST_IRQ(1, priority),
646 uart_stellaris_isr, DEVICE_DT_INST_GET(1),
647 0);
648 irq_enable(DT_INST_IRQN(1));
649 }
650 #endif
651
652 #endif /* CONFIG_UART_STELLARIS_PORT_1 */
653
654 #ifdef CONFIG_UART_STELLARIS_PORT_2
655
656 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
657 static void irq_config_func_2(const struct device *port);
658 #endif
659
660 static const struct uart_stellaris_config uart_stellaris_dev_cfg_2 = {
661 .uart = (volatile struct _uart *)DT_INST_REG_ADDR(2),
662 .sys_clk_freq = DT_INST_PROP_BY_PHANDLE(2, clocks, clock_frequency),
663
664 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
665 .irq_config_func = irq_config_func_2,
666 #endif
667 };
668
669 static struct uart_stellaris_dev_data_t uart_stellaris_dev_data_2 = {
670 .baud_rate = DT_INST_PROP(2, current_speed),
671 };
672
673 DEVICE_DT_INST_DEFINE(2,
674 uart_stellaris_init,
675 NULL,
676 &uart_stellaris_dev_data_2, &uart_stellaris_dev_cfg_2,
677 PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY,
678 &uart_stellaris_driver_api);
679
680 #ifdef CONFIG_UART_INTERRUPT_DRIVEN
irq_config_func_2(const struct device * dev)681 static void irq_config_func_2(const struct device *dev)
682 {
683 IRQ_CONNECT(DT_INST_IRQN(2),
684 DT_INST_IRQ(2, priority),
685 uart_stellaris_isr, DEVICE_DT_INST_GET(2),
686 0);
687 irq_enable(DT_INST_IRQN(2));
688 }
689 #endif
690
691 #endif /* CONFIG_UART_STELLARIS_PORT_2 */
692