source: rtems/c/src/lib/libbsp/arm/lpc32xx/console/hsu.c @ 22f107b6

4.104.115
Last change on this file since 22f107b6 was 22f107b6, checked in by Thomas Doerfler <Thomas.Doerfler@…>, on 04/09/10 at 12:25:22

Changes throughout

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