Skip to content

Commit 296fb5b

Browse files
committed
drivers: serial: add amebadplus loguart driver
loguart driver for amebadplus Signed-off-by: zjian zhang <zjian_zhang@realsil.com.cn>
1 parent 38f66e4 commit 296fb5b

File tree

5 files changed

+355
-0
lines changed

5 files changed

+355
-0
lines changed

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ zephyr_library_sources_ifdef(CONFIG_SERIAL_ESP32_USB serial_esp32_usb.c)
2020
zephyr_library_sources_ifdef(CONFIG_UART_AESC uart_aesc.c)
2121
zephyr_library_sources_ifdef(CONFIG_UART_ALTERA uart_altera.c)
2222
zephyr_library_sources_ifdef(CONFIG_UART_ALTERA_JTAG uart_altera_jtag.c)
23+
zephyr_library_sources_ifdef(CONFIG_UART_AMEBA_LOGUART uart_ameba_loguart.c)
2324
zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c)
2425
zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c)
2526
zephyr_library_sources_ifdef(CONFIG_UART_BFLB uart_bflb.c)

drivers/serial/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ comment "Serial Drivers"
160160
rsource "Kconfig.aesc"
161161
rsource "Kconfig.altera"
162162
rsource "Kconfig.altera_jtag"
163+
rsource "Kconfig.ameba_loguart"
163164
rsource "Kconfig.apbuart"
164165
rsource "Kconfig.b91"
165166
rsource "Kconfig.bcm2711"

drivers/serial/Kconfig.ameba_loguart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2024 Realtek Semiconductor Corp.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config UART_AMEBA_LOGUART
5+
bool "Ameba LOGUART driver"
6+
default y
7+
depends on DT_HAS_REALTEK_AMEBA_LOGUART_ENABLED
8+
select SERIAL_HAS_DRIVER
9+
help
10+
This option enables the LOGUART driver for Realtek Ameba SoCs.

drivers/serial/uart_ameba_loguart.c

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
/*
2+
* Copyright (c) 2024 Realtek Semiconductor Corp.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @brief Driver for Realtek Ameba LOGUART
9+
*/
10+
11+
/* Include <soc.h> before <ameba_soc.h> to avoid redefining unlikely() macro */
12+
#include <soc.h>
13+
#include <ameba_soc.h>
14+
15+
#include <zephyr/drivers/uart.h>
16+
#include <zephyr/drivers/clock_control.h>
17+
#include <zephyr/drivers/pinctrl.h>
18+
#include <zephyr/irq.h>
19+
20+
#include <zephyr/logging/log.h>
21+
LOG_MODULE_REGISTER(loguart_ameba, CONFIG_UART_LOG_LEVEL);
22+
23+
/*
24+
* Extract information from devicetree.
25+
*
26+
* This driver only supports one instance of this IP block, so the
27+
* instance number is always 0.
28+
*/
29+
#define DT_DRV_COMPAT realtek_ameba_loguart
30+
31+
/* Device config structure */
32+
struct loguart_ameba_config {
33+
#if defined(CONFIG_UART_INTERRUPT_DRIVEN)
34+
uart_irq_config_func_t irq_config_func;
35+
#endif
36+
};
37+
38+
/* Device data structure */
39+
struct loguart_ameba_data {
40+
struct uart_config config;
41+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
42+
uart_irq_callback_user_data_t user_cb;
43+
void *user_data;
44+
bool tx_int_en;
45+
bool rx_int_en;
46+
#endif
47+
};
48+
49+
/**
50+
* @brief Poll the device for input.
51+
*
52+
* @param dev UART device struct
53+
* @param c Pointer to character
54+
*
55+
* @return 0 if a character arrived, -1 if the input buffer if empty.
56+
*/
57+
static int loguart_ameba_poll_in(const struct device *dev, unsigned char *c)
58+
{
59+
ARG_UNUSED(dev);
60+
61+
if (!LOGUART_Readable()) {
62+
return -1;
63+
}
64+
65+
*c = LOGUART_GetChar(false);
66+
return 0;
67+
}
68+
69+
/**
70+
* @brief Output a character in polled mode.
71+
*
72+
* @param dev UART device struct
73+
* @param c Character to send
74+
*/
75+
static void loguart_ameba_poll_out(const struct device *dev, unsigned char c)
76+
{
77+
ARG_UNUSED(dev);
78+
LOGUART_PutChar(c);
79+
}
80+
81+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
82+
83+
static int loguart_ameba_fifo_fill(const struct device *dev, const uint8_t *tx_data, int len)
84+
{
85+
ARG_UNUSED(dev);
86+
87+
uint8_t num_tx = 0U;
88+
unsigned int key;
89+
90+
if (!LOGUART_Writable()) {
91+
return num_tx;
92+
}
93+
94+
/* Lock interrupts to prevent nested interrupts or thread switch */
95+
96+
key = irq_lock();
97+
98+
while ((len - num_tx > 0) && LOGUART_Writable()) {
99+
LOGUART_PutChar((uint8_t)tx_data[num_tx++]);
100+
}
101+
102+
irq_unlock(key);
103+
104+
return num_tx;
105+
}
106+
107+
static int loguart_ameba_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
108+
{
109+
ARG_UNUSED(dev);
110+
111+
uint8_t num_rx = 0U;
112+
113+
while ((size - num_rx > 0) && LOGUART_Readable()) {
114+
rx_data[num_rx++] = LOGUART_GetChar(false);
115+
}
116+
117+
/* Clear timeout int flag */
118+
if (LOGUART_GetStatus(LOGUART_DEV) & LOGUART_BIT_TIMEOUT_INT) {
119+
LOGUART_INTClear(LOGUART_DEV, LOGUART_BIT_TOICF);
120+
}
121+
122+
return num_rx;
123+
}
124+
125+
static void loguart_ameba_irq_tx_enable(const struct device *dev)
126+
{
127+
u32 sts;
128+
struct loguart_ameba_data *data = dev->data;
129+
130+
/* Disable IRQ Interrupts and Save Previous Status. */
131+
sts = irq_disable_save();
132+
133+
data->tx_int_en = true;
134+
/* KM4: TX_PATH1 */
135+
LOGUART_INTConfig(LOGUART_DEV, LOGUART_TX_EMPTY_PATH_1_INTR, ENABLE);
136+
137+
/* Enable IRQ Interrupts according to Previous Status. */
138+
irq_enable_restore(sts);
139+
}
140+
141+
static void loguart_ameba_irq_tx_disable(const struct device *dev)
142+
{
143+
u32 sts;
144+
struct loguart_ameba_data *data = dev->data;
145+
146+
/* Disable IRQ Interrupts and Save Previous Status. */
147+
sts = irq_disable_save();
148+
149+
LOGUART_INTConfig(LOGUART_DEV, LOGUART_TX_EMPTY_PATH_1_INTR, DISABLE);
150+
data->tx_int_en = false;
151+
152+
/* Enable IRQ Interrupts according to Previous Status. */
153+
irq_enable_restore(sts);
154+
}
155+
156+
static int loguart_ameba_irq_tx_ready(const struct device *dev)
157+
{
158+
struct loguart_ameba_data *data = dev->data;
159+
160+
/* KM4: TX_PATH1 */
161+
return (LOGUART_GetStatus(LOGUART_DEV) & LOGUART_BIT_TP1F_EMPTY) && data->tx_int_en;
162+
}
163+
164+
static int loguart_ameba_irq_tx_complete(const struct device *dev)
165+
{
166+
return loguart_ameba_irq_tx_ready(dev);
167+
}
168+
169+
static void loguart_ameba_irq_rx_enable(const struct device *dev)
170+
{
171+
struct loguart_ameba_data *data = dev->data;
172+
173+
data->rx_int_en = true;
174+
LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ERBI | LOGUART_BIT_ETOI, ENABLE);
175+
}
176+
177+
static void loguart_ameba_irq_rx_disable(const struct device *dev)
178+
{
179+
struct loguart_ameba_data *data = dev->data;
180+
181+
data->rx_int_en = false;
182+
LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ERBI | LOGUART_BIT_ETOI, DISABLE);
183+
}
184+
185+
static int loguart_ameba_irq_rx_ready(const struct device *dev)
186+
{
187+
struct loguart_ameba_data *data = dev->data;
188+
189+
return (LOGUART_GetStatus(LOGUART_DEV) &
190+
(LOGUART_BIT_DRDY | LOGUART_BIT_RXFIFO_INT | LOGUART_BIT_TIMEOUT_INT)) &&
191+
data->rx_int_en;
192+
}
193+
194+
static void loguart_ameba_irq_err_enable(const struct device *dev)
195+
{
196+
ARG_UNUSED(dev);
197+
198+
LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ELSI, ENABLE);
199+
}
200+
201+
static void loguart_ameba_irq_err_disable(const struct device *dev)
202+
{
203+
ARG_UNUSED(dev);
204+
205+
LOGUART_INTConfig(LOGUART_DEV, LOGUART_BIT_ELSI, DISABLE);
206+
}
207+
208+
static int loguart_ameba_irq_is_pending(const struct device *dev)
209+
{
210+
struct loguart_ameba_data *data = dev->data;
211+
212+
return ((LOGUART_GetStatus(LOGUART_DEV) & LOGUART_BIT_TP1F_EMPTY) && data->tx_int_en) ||
213+
((LOGUART_GetStatus(LOGUART_DEV) &
214+
(LOGUART_BIT_DRDY | LOGUART_BIT_RXFIFO_INT | LOGUART_BIT_TIMEOUT_INT)) &&
215+
data->rx_int_en);
216+
}
217+
218+
static int loguart_ameba_irq_update(const struct device *dev)
219+
{
220+
return 1;
221+
}
222+
223+
static void loguart_ameba_irq_callback_set(const struct device *dev,
224+
uart_irq_callback_user_data_t cb, void *cb_data)
225+
{
226+
struct loguart_ameba_data *data = dev->data;
227+
228+
data->user_cb = cb;
229+
data->user_data = cb_data;
230+
}
231+
232+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
233+
234+
/**
235+
* @brief Initialize UART channel
236+
*
237+
* This routine is called to reset the chip in a quiescent state.
238+
* It is assumed that this function is called only once per UART.
239+
*
240+
* @param dev UART device struct
241+
*
242+
* @return 0 on success
243+
*/
244+
static int loguart_ameba_init(const struct device *dev)
245+
{
246+
LOGUART_RxCmd(LOGUART_DEV, DISABLE);
247+
LOGUART_INTCoreConfig(LOGUART_DEV, LOGUART_BIT_INTR_MASK_KM0, DISABLE);
248+
LOGUART_INTCoreConfig(LOGUART_DEV, LOGUART_BIT_INTR_MASK_KM4, ENABLE);
249+
250+
#if defined(CONFIG_UART_INTERRUPT_DRIVEN)
251+
const struct loguart_ameba_config *config = dev->config;
252+
253+
config->irq_config_func(dev);
254+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
255+
256+
LOGUART_RxCmd(LOGUART_DEV, ENABLE);
257+
258+
return 0;
259+
}
260+
261+
#if defined(CONFIG_UART_INTERRUPT_DRIVEN)
262+
#define AMEBA_LOGUART_IRQ_HANDLER_DECL \
263+
static void loguart_ameba_irq_config_func(const struct device *dev);
264+
#define AMEBA_LOGUART_IRQ_HANDLER \
265+
static void loguart_ameba_irq_config_func(const struct device *dev) \
266+
{ \
267+
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), loguart_ameba_isr, \
268+
DEVICE_DT_INST_GET(0), 0); \
269+
irq_enable(DT_INST_IRQN(0)); \
270+
}
271+
#define AMEBA_LOGUART_IRQ_HANDLER_FUNC .irq_config_func = loguart_ameba_irq_config_func,
272+
#else
273+
#define AMEBA_LOGUART_IRQ_HANDLER_DECL /* Not used */
274+
#define AMEBA_LOGUART_IRQ_HANDLER /* Not used */
275+
#define AMEBA_LOGUART_IRQ_HANDLER_FUNC /* Not used */
276+
#endif
277+
278+
#if defined(CONFIG_UART_INTERRUPT_DRIVEN)
279+
280+
static void loguart_ameba_isr(const struct device *dev)
281+
{
282+
struct loguart_ameba_data *data = dev->data;
283+
284+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
285+
if (data->user_cb) {
286+
data->user_cb(dev, data->user_data);
287+
}
288+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
289+
}
290+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
291+
292+
static const struct uart_driver_api loguart_ameba_driver_api = {
293+
.poll_in = loguart_ameba_poll_in,
294+
.poll_out = loguart_ameba_poll_out,
295+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
296+
.fifo_fill = loguart_ameba_fifo_fill,
297+
.fifo_read = loguart_ameba_fifo_read,
298+
.irq_tx_enable = loguart_ameba_irq_tx_enable,
299+
.irq_tx_disable = loguart_ameba_irq_tx_disable,
300+
.irq_tx_ready = loguart_ameba_irq_tx_ready,
301+
.irq_rx_enable = loguart_ameba_irq_rx_enable,
302+
.irq_rx_disable = loguart_ameba_irq_rx_disable,
303+
.irq_tx_complete = loguart_ameba_irq_tx_complete,
304+
.irq_rx_ready = loguart_ameba_irq_rx_ready,
305+
.irq_err_enable = loguart_ameba_irq_err_enable,
306+
.irq_err_disable = loguart_ameba_irq_err_disable,
307+
.irq_is_pending = loguart_ameba_irq_is_pending,
308+
.irq_update = loguart_ameba_irq_update,
309+
.irq_callback_set = loguart_ameba_irq_callback_set,
310+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
311+
};
312+
313+
AMEBA_LOGUART_IRQ_HANDLER_DECL
314+
AMEBA_LOGUART_IRQ_HANDLER
315+
316+
static const struct loguart_ameba_config loguart_config = {AMEBA_LOGUART_IRQ_HANDLER_FUNC};
317+
318+
static struct loguart_ameba_data loguart_data = {.config = {
319+
.stop_bits = UART_CFG_STOP_BITS_1,
320+
.data_bits = UART_CFG_DATA_BITS_8,
321+
.baudrate = DT_INST_PROP(0, current_speed),
322+
.parity = UART_CFG_PARITY_NONE,
323+
.flow_ctrl = UART_CFG_FLOW_CTRL_NONE,
324+
}};
325+
326+
DEVICE_DT_INST_DEFINE(0, loguart_ameba_init, NULL, &loguart_data, &loguart_config, PRE_KERNEL_1,
327+
CONFIG_SERIAL_INIT_PRIORITY, &loguart_ameba_driver_api);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Copyright (c) 2024 Realtek Semiconductor Corp.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Ameba LOGUART
5+
compatible: "realtek,ameba-loguart"
6+
7+
include: [uart-controller.yaml, base.yaml, pinctrl-device.yaml]
8+
9+
bus: uart
10+
11+
properties:
12+
reg:
13+
required: true
14+
15+
interrupts:
16+
required: true

0 commit comments

Comments
 (0)