Skip to content

Commit 43f311b

Browse files
ene-stevenkartben
authored andcommitted
drivers: uart: uart driver
Add uart driver for ENE KB1200 Signed-off-by: Steven Chang <[email protected]>
1 parent 7d2be3b commit 43f311b

File tree

6 files changed

+380
-0
lines changed

6 files changed

+380
-0
lines changed

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_CDNS uart_cdns.c)
3333
zephyr_library_sources_ifdef(CONFIG_UART_CMSDK_APB uart_cmsdk_apb.c)
3434
zephyr_library_sources_ifdef(CONFIG_UART_EFINIX_SAPPIHIRE uart_efinix_sapphire.c)
3535
zephyr_library_sources_ifdef(CONFIG_UART_EMUL uart_emul.c)
36+
zephyr_library_sources_ifdef(CONFIG_UART_ENE_KB106X uart_ene_kb106x.c)
3637
zephyr_library_sources_ifdef(CONFIG_UART_ENE_KB1200 uart_ene_kb1200.c)
3738
zephyr_library_sources_ifdef(CONFIG_UART_ESP32 uart_esp32.c)
3839
zephyr_library_sources_ifdef(CONFIG_UART_GECKO uart_gecko.c)

drivers/serial/Kconfig.ene

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,13 @@ config UART_ENE_KB1200
1010
select PINCTRL
1111
help
1212
This option enables the KB1200 serial driver.
13+
14+
config UART_ENE_KB106X
15+
bool "ENE KB106X serial driver"
16+
default y
17+
depends on DT_HAS_ENE_KB106X_UART_ENABLED
18+
select SERIAL_HAS_DRIVER
19+
select SERIAL_SUPPORT_INTERRUPT
20+
select PINCTRL
21+
help
22+
This option enables the KB106X serial driver.

drivers/serial/uart_ene_kb106x.c

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
/*
2+
* Copyright (c) 2025 ENE Technology Inc.
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ene_kb106x_uart
8+
9+
#include <zephyr/kernel.h>
10+
#include <zephyr/drivers/uart.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
#include <reg/ser.h>
13+
14+
struct kb106x_uart_config {
15+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
16+
void (*irq_cfg_func)(void);
17+
#endif
18+
struct serial_regs *ser;
19+
const struct pinctrl_dev_config *pcfg;
20+
};
21+
22+
struct kb106x_uart_data {
23+
uart_irq_callback_user_data_t callback;
24+
struct uart_config current_config;
25+
void *callback_data;
26+
uint8_t pending_flag_data;
27+
};
28+
29+
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
30+
static int kb106x_uart_configure(const struct device *dev, const struct uart_config *cfg)
31+
{
32+
uint16_t reg_baudrate = 0;
33+
int ret = 0;
34+
const struct kb106x_uart_config *config = dev->config;
35+
struct kb106x_uart_data *data = dev->data;
36+
37+
reg_baudrate = (DIVIDER_BASE_CLK / cfg->baudrate) - 1;
38+
39+
switch (cfg->parity) {
40+
case UART_CFG_PARITY_NONE:
41+
break;
42+
case UART_CFG_PARITY_ODD:
43+
case UART_CFG_PARITY_EVEN:
44+
case UART_CFG_PARITY_MARK:
45+
case UART_CFG_PARITY_SPACE:
46+
default:
47+
ret = -ENOTSUP;
48+
break;
49+
}
50+
51+
switch (cfg->stop_bits) {
52+
case UART_CFG_STOP_BITS_1:
53+
break;
54+
case UART_CFG_STOP_BITS_0_5:
55+
case UART_CFG_STOP_BITS_1_5:
56+
case UART_CFG_STOP_BITS_2:
57+
default:
58+
ret = -ENOTSUP;
59+
break;
60+
}
61+
62+
switch (cfg->data_bits) {
63+
case UART_CFG_DATA_BITS_8:
64+
break;
65+
case UART_CFG_DATA_BITS_5:
66+
case UART_CFG_DATA_BITS_6:
67+
case UART_CFG_DATA_BITS_7:
68+
case UART_CFG_DATA_BITS_9:
69+
default:
70+
ret = -ENOTSUP;
71+
break;
72+
}
73+
74+
switch (cfg->flow_ctrl) {
75+
case UART_CFG_FLOW_CTRL_NONE:
76+
break;
77+
case UART_CFG_FLOW_CTRL_RTS_CTS:
78+
case UART_CFG_FLOW_CTRL_DTR_DSR:
79+
default:
80+
ret = -ENOTSUP;
81+
break;
82+
}
83+
config->ser->SERCFG = (reg_baudrate << 16) | 0x04 | SERIE_TX_ENABLE;
84+
config->ser->SERCTRL = SERCTRL_MODE1;
85+
data->current_config = *cfg;
86+
return ret;
87+
}
88+
89+
static int kb106x_uart_config_get(const struct device *dev, struct uart_config *cfg)
90+
{
91+
struct kb106x_uart_data *data = dev->data;
92+
93+
*cfg = data->current_config;
94+
return 0;
95+
}
96+
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
97+
98+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
99+
static int kb106x_uart_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
100+
{
101+
const struct kb106x_uart_config *config = dev->config;
102+
uint16_t tx_bytes = 0U;
103+
104+
while ((size - tx_bytes) > 0) {
105+
/* Check Tx FIFO not Full*/
106+
while (config->ser->SERSTS & SERSTS_TX_FULL) {
107+
}
108+
/* Put a character into Tx FIFO */
109+
config->ser->SERTBUF = tx_data[tx_bytes];
110+
tx_bytes++;
111+
}
112+
return tx_bytes;
113+
}
114+
115+
static void kb106x_uart_irq_tx_enable(const struct device *dev)
116+
{
117+
const struct kb106x_uart_config *config = dev->config;
118+
119+
config->ser->SERPF = SERPF_TX_EMPTY;
120+
config->ser->SERIE |= SERIE_TX_ENABLE;
121+
}
122+
123+
static void kb106x_uart_irq_tx_disable(const struct device *dev)
124+
{
125+
const struct kb106x_uart_config *config = dev->config;
126+
127+
config->ser->SERIE &= ~SERIE_TX_ENABLE;
128+
config->ser->SERPF = SERPF_TX_EMPTY;
129+
}
130+
131+
static int kb106x_uart_irq_tx_ready(const struct device *dev)
132+
{
133+
struct kb106x_uart_data *data = dev->data;
134+
135+
return (data->pending_flag_data & SERPF_TX_EMPTY) ? 1 : 0;
136+
}
137+
138+
static int kb106x_uart_irq_is_pending(const struct device *dev)
139+
{
140+
struct kb106x_uart_data *data = dev->data;
141+
142+
return (data->pending_flag_data) ? 1 : 0;
143+
}
144+
145+
static int kb106x_uart_irq_update(const struct device *dev)
146+
{
147+
struct kb106x_uart_data *data = dev->data;
148+
const struct kb106x_uart_config *config = dev->config;
149+
150+
data->pending_flag_data = (config->ser->SERPF) & (config->ser->SERIE);
151+
/*clear pending flag*/
152+
config->ser->SERPF = data->pending_flag_data;
153+
return 1;
154+
}
155+
156+
static void kb106x_uart_irq_callback_set(const struct device *dev, uart_irq_callback_user_data_t cb,
157+
void *cb_data)
158+
{
159+
struct kb106x_uart_data *data = dev->data;
160+
161+
data->callback = cb;
162+
data->callback_data = cb_data;
163+
}
164+
165+
static void kb106x_uart_irq_handler(const struct device *dev)
166+
{
167+
struct kb106x_uart_data *data = dev->data;
168+
169+
if (data->callback) {
170+
data->callback(dev, data->callback_data);
171+
}
172+
}
173+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
174+
175+
static int kb106x_uart_poll_in(const struct device *dev, unsigned char *c)
176+
{
177+
const struct kb106x_uart_config *config = dev->config;
178+
179+
/* Check Rx FIFO not Empty*/
180+
if (config->ser->SERSTS & SERSTS_RX_BUSY) {
181+
return -1;
182+
}
183+
/* Put a character into Tx FIFO */
184+
*c = config->ser->SERRBUF;
185+
return 0;
186+
}
187+
188+
static void kb106x_uart_poll_out(const struct device *dev, unsigned char c)
189+
{
190+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
191+
kb106x_uart_fifo_fill(dev, &c, 1);
192+
#else
193+
const struct kb106x_uart_config *config = dev->config;
194+
195+
/* Wait Tx FIFO not Full*/
196+
while (config->ser->SERSTS & SERSTS_TX_FULL) {
197+
}
198+
/* Put a character into Tx FIFO */
199+
config->ser->SERTBUF = c;
200+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
201+
}
202+
203+
static DEVICE_API(uart, kb106x_uart_api) = {
204+
.poll_in = kb106x_uart_poll_in,
205+
.poll_out = kb106x_uart_poll_out,
206+
#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
207+
.configure = kb106x_uart_configure,
208+
.config_get = kb106x_uart_config_get,
209+
#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
210+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
211+
.fifo_fill = kb106x_uart_fifo_fill,
212+
.irq_tx_enable = kb106x_uart_irq_tx_enable,
213+
.irq_tx_disable = kb106x_uart_irq_tx_disable,
214+
.irq_tx_ready = kb106x_uart_irq_tx_ready,
215+
.irq_is_pending = kb106x_uart_irq_is_pending,
216+
.irq_update = kb106x_uart_irq_update,
217+
.irq_callback_set = kb106x_uart_irq_callback_set,
218+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
219+
};
220+
221+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
222+
223+
/* GPIO module instances */
224+
#define KB106X_UART_DEV(inst) DEVICE_DT_INST_GET(inst),
225+
static const struct device *const uart_devices[] = {DT_INST_FOREACH_STATUS_OKAY(KB106X_UART_DEV)};
226+
static void kb106x_uart_isr_wrap(const struct device *dev)
227+
{
228+
for (size_t i = 0; i < ARRAY_SIZE(uart_devices); i++) {
229+
const struct device *dev_ = uart_devices[i];
230+
const struct kb106x_uart_config *config = dev_->config;
231+
232+
if (config->ser->SERIE & config->ser->SERPF) {
233+
kb106x_uart_irq_handler(dev_);
234+
}
235+
}
236+
}
237+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
238+
239+
static int kb106x_uart_init(const struct device *dev)
240+
{
241+
int ret;
242+
const struct kb106x_uart_config *config = dev->config;
243+
struct kb106x_uart_data *data = dev->data;
244+
245+
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
246+
if (ret != 0) {
247+
return ret;
248+
}
249+
250+
kb106x_uart_configure(dev, &data->current_config);
251+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
252+
config->irq_cfg_func();
253+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
254+
255+
return 0;
256+
}
257+
258+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
259+
static bool init_irq = true;
260+
static void kb106x_uart_irq_init(void)
261+
{
262+
if (init_irq) {
263+
init_irq = false;
264+
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), kb106x_uart_isr_wrap, NULL,
265+
0);
266+
irq_enable(DT_INST_IRQN(0));
267+
}
268+
}
269+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
270+
271+
#define KB106X_UART_INIT(n) \
272+
PINCTRL_DT_INST_DEFINE(n); \
273+
static struct kb106x_uart_data kb106x_uart_data_##n = { \
274+
.current_config = { \
275+
.baudrate = DT_INST_PROP(n, current_speed), \
276+
.parity = UART_CFG_PARITY_NONE, \
277+
.stop_bits = UART_CFG_STOP_BITS_1, \
278+
.data_bits = UART_CFG_DATA_BITS_8, \
279+
.flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \
280+
}, \
281+
}; \
282+
static const struct kb106x_uart_config kb106x_uart_config_##n = { \
283+
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, (.irq_cfg_func = kb106x_uart_irq_init,)) \
284+
.ser = (struct serial_regs *)DT_INST_REG_ADDR(n), \
285+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
286+
}; \
287+
DEVICE_DT_INST_DEFINE(n, &kb106x_uart_init, NULL, &kb106x_uart_data_##n, \
288+
&kb106x_uart_config_##n, PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
289+
&kb106x_uart_api);
290+
291+
DT_INST_FOREACH_STATUS_OKAY(KB106X_UART_INIT)

dts/arm/ene/kb106x/kb106x.dtsi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@
111111
status = "disabled";
112112
};
113113
};
114+
115+
uart0: serial@40310000 {
116+
compatible = "ene,kb106x-uart";
117+
reg = <0x40310000 0x4c>;
118+
interrupts = <18 3>;
119+
status = "disabled";
120+
};
114121
};
115122
};
116123

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Copyright (c) 2025 ENE Technology Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ENE KB106X UART
5+
6+
compatible: "ene,kb106x-uart"
7+
8+
include: [uart-controller.yaml, pinctrl-device.yaml]
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
interrupts:
15+
required: true
16+
17+
current-speed:
18+
required: true
19+
20+
pinctrl-0:
21+
required: true
22+
23+
pinctrl-names:
24+
required: true

0 commit comments

Comments
 (0)