Skip to content

Commit 799198b

Browse files
committed
drivers: serial: add amebad loguart driver
loguart driver for amebad Signed-off-by: zjian zhang <zjian_zhang@realsil.com.cn>
1 parent 0750268 commit 799198b

File tree

5 files changed

+348
-0
lines changed

5 files changed

+348
-0
lines changed

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ 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)
2323
zephyr_library_sources_ifdef(CONFIG_UART_AMBIQ uart_ambiq.c)
24+
zephyr_library_sources_ifdef(CONFIG_UART_AMEBA_LOGUART uart_ameba_loguart.c)
2425
zephyr_library_sources_ifdef(CONFIG_UART_APBUART uart_apbuart.c)
2526
zephyr_library_sources_ifdef(CONFIG_UART_BCM2711_MU uart_bcm2711.c)
2627
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
@@ -161,6 +161,7 @@ rsource "Kconfig.aesc"
161161
rsource "Kconfig.altera"
162162
rsource "Kconfig.altera_jtag"
163163
rsource "Kconfig.ambiq"
164+
rsource "Kconfig.ameba_loguart"
164165
rsource "Kconfig.apbuart"
165166
rsource "Kconfig.b91"
166167
rsource "Kconfig.bcm2711"

drivers/serial/Kconfig.ameba_loguart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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+
select SERIAL_SUPPORT_INTERRUPT
10+
help
11+
This option enables the LOGUART driver for Realtek Ameba SoCs.

drivers/serial/uart_ameba_loguart.c

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