source: rtems/bsps/arm/lpc32xx/console/hsu.c @ ba619b7f

Last change on this file since ba619b7f was ba619b7f, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:20

bsps/arm/: Scripted embedded brains header file clean up

Updates #4625.

  • Property mode set to 100644
File size: 4.6 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup RTEMSBSPsARMLPC32XX
5 *
6 * @brief High speed UART driver (14-clock).
7 */
8
9/*
10 * Copyright (c) 2010-2014 embedded brains GmbH.  All rights reserved.
11 *
12 * The license and distribution terms for this file may be
13 * found in the file LICENSE in this distribution or at
14 * http://www.rtems.org/license/LICENSE.
15 */
16
17#include <bsp.h>
18#include <bsp/lpc32xx.h>
19#include <bsp/irq.h>
20#include <bsp/hsu.h>
21
22#define HSU_FIFO_SIZE 64
23
24#define HSU_LEVEL_RX_MASK 0xffU
25#define HSU_LEVEL_TX_MASK 0xff00U
26#define HSU_LEVEL_TX_SHIFT 8
27
28#define HSU_RX_DATA_MASK 0xffU
29#define HSU_RX_EMPTY (1U << 8)
30#define HSU_RX_ERROR (1U << 9)
31#define HSU_RX_BREAK (1U << 10)
32
33#define HSU_IIR_TX (1U << 0)
34#define HSU_IIR_RX_TRIG (1U << 1)
35#define HSU_IIR_RX_TIMEOUT (1U << 2)
36
37#define HSU_CTRL_INTR_DISABLED 0x1280fU
38#define HSU_CTRL_RX_INTR_ENABLED 0x1284fU
39#define HSU_CTRL_RX_AND_TX_INTR_ENABLED 0x1286fU
40
41/* We are interested in RX timeout, RX trigger and TX trigger interrupts */
42#define HSU_IIR_MASK 0x7U
43
44bool lpc32xx_hsu_probe(rtems_termios_device_context *base)
45{
46  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
47  volatile lpc32xx_hsu *hsu = ctx->hsu;
48
49  hsu->ctrl = HSU_CTRL_INTR_DISABLED;
50
51  /* Drain FIFOs */
52  while (hsu->level != 0) {
53    hsu->fifo;
54  }
55
56  return true;
57}
58
59static void lpc32xx_hsu_interrupt_handler(void *arg)
60{
61  rtems_termios_tty *tty = arg;
62  lpc32xx_hsu_context *ctx = rtems_termios_get_device_context(tty);
63  volatile lpc32xx_hsu *hsu = ctx->hsu;
64
65  /* Iterate until no more interrupts are pending */
66  do {
67    int rv = 0;
68    int i = 0;
69    char buf [HSU_FIFO_SIZE];
70
71    /* Enqueue received characters */
72    while (i < HSU_FIFO_SIZE) {
73      uint32_t in = hsu->fifo;
74
75      if ((in & HSU_RX_EMPTY) == 0) {
76        if ((in & HSU_RX_BREAK) == 0) {
77          buf [i] = in & HSU_RX_DATA_MASK;
78          ++i;
79        }
80      } else {
81        break;
82      }
83    }
84    rtems_termios_enqueue_raw_characters(tty, buf, i);
85
86    /* Dequeue transmitted characters */
87    rv = rtems_termios_dequeue_characters(tty, (int) ctx->chars_in_transmission);
88    if (rv == 0) {
89      /* Nothing to transmit */
90    }
91  } while ((hsu->iir & HSU_IIR_MASK) != 0);
92}
93
94static bool lpc32xx_hsu_first_open(
95  struct rtems_termios_tty *tty,
96  rtems_termios_device_context *base,
97  struct termios *term,
98  rtems_libio_open_close_args_t *args
99)
100{
101  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
102  volatile lpc32xx_hsu *hsu = ctx->hsu;
103  rtems_status_code sc;
104  bool ok;
105
106  sc = rtems_interrupt_handler_install(
107    ctx->irq,
108    "HSU",
109    RTEMS_INTERRUPT_UNIQUE,
110    lpc32xx_hsu_interrupt_handler,
111    tty
112  );
113  ok = sc == RTEMS_SUCCESSFUL;
114
115  if (ok) {
116    rtems_termios_set_initial_baud(tty, ctx->initial_baud);
117    hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED;
118  }
119
120  return ok;
121}
122
123static void lpc32xx_hsu_last_close(
124  struct rtems_termios_tty *tty,
125  rtems_termios_device_context *base,
126  rtems_libio_open_close_args_t *args
127)
128{
129  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
130  volatile lpc32xx_hsu *hsu = ctx->hsu;
131
132  hsu->ctrl = HSU_CTRL_INTR_DISABLED;
133
134  rtems_interrupt_handler_remove(
135    ctx->irq,
136    lpc32xx_hsu_interrupt_handler,
137    tty
138  );
139}
140
141static void lpc32xx_hsu_write(
142  rtems_termios_device_context *base,
143  const char *buf,
144  size_t len
145)
146{
147  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
148  volatile lpc32xx_hsu *hsu = ctx->hsu;
149  size_t tx_level = (hsu->level & HSU_LEVEL_TX_MASK) >> HSU_LEVEL_TX_SHIFT;
150  size_t tx_free = HSU_FIFO_SIZE - tx_level;
151  size_t i = 0;
152  size_t out = len > tx_free ? tx_free : len;
153
154  for (i = 0; i < out; ++i) {
155    hsu->fifo = buf [i];
156  }
157
158  ctx->chars_in_transmission = out;
159
160  if (len > 0) {
161    hsu->ctrl = HSU_CTRL_RX_AND_TX_INTR_ENABLED;
162  } else {
163    hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED;
164    hsu->iir = HSU_IIR_TX;
165  }
166}
167
168static bool lpc32xx_hsu_set_attributes(
169  rtems_termios_device_context *base,
170  const struct termios *term
171)
172{
173  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
174  volatile lpc32xx_hsu *hsu = ctx->hsu;
175  int baud_flags = term->c_ospeed;
176
177  if (baud_flags != 0) {
178    int32_t baud = rtems_termios_baud_to_number(baud_flags);
179
180    if (baud > 0) {
181      uint32_t baud_divisor = 14 * (uint32_t) baud;
182      uint32_t rate = LPC32XX_PERIPH_CLK / baud_divisor;
183      uint32_t remainder = LPC32XX_PERIPH_CLK - rate * baud_divisor;
184
185      if (2 * remainder >= baud_divisor) {
186        ++rate;
187      }
188
189      hsu->rate = rate - 1;
190    }
191  }
192
193  return true;
194}
195
196const rtems_termios_device_handler lpc32xx_hsu_fns = {
197  .first_open = lpc32xx_hsu_first_open,
198  .last_close = lpc32xx_hsu_last_close,
199  .write = lpc32xx_hsu_write,
200  .set_attributes = lpc32xx_hsu_set_attributes,
201  .mode = TERMIOS_IRQ_DRIVEN
202};
Note: See TracBrowser for help on using the repository browser.