Skip to content

Commit e3e2a40

Browse files
gmarullkartben
authored andcommitted
drivers: serial: sf32lb: add basic driver
Just basic driver with poll-in/out capability. Signed-off-by: Gerard Marull-Paretas <[email protected]>
1 parent 8e17e6d commit e3e2a40

File tree

4 files changed

+253
-0
lines changed

4 files changed

+253
-0
lines changed

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_SAM uart_sam.c)
8787
zephyr_library_sources_ifdef(CONFIG_UART_SAM0 uart_sam0.c)
8888
zephyr_library_sources_ifdef(CONFIG_UART_SCI_RA uart_renesas_ra_sci.c)
8989
zephyr_library_sources_ifdef(CONFIG_UART_SEDI uart_sedi.c)
90+
zephyr_library_sources_ifdef(CONFIG_UART_SF32LB uart_sf32lb.c)
9091
zephyr_library_sources_ifdef(CONFIG_UART_SI32_USART uart_si32_usart.c)
9192
zephyr_library_sources_ifdef(CONFIG_UART_SIFIVE uart_sifive.c)
9293
zephyr_library_sources_ifdef(CONFIG_UART_SILABS_EUSART uart_silabs_eusart.c)

drivers/serial/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ rsource "Kconfig.rv32m1_lpuart"
225225
rsource "Kconfig.rzt2m"
226226
rsource "Kconfig.sam0"
227227
rsource "Kconfig.sedi"
228+
rsource "Kconfig.sf32lb"
228229
rsource "Kconfig.si32"
229230
rsource "Kconfig.sifive"
230231
rsource "Kconfig.silabs_eusart"

drivers/serial/Kconfig.sf32lb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright (c) Core Devices LLC
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config UART_SF32LB
5+
bool "SiFli SF32LB UART driver"
6+
default y
7+
depends on DT_HAS_SIFLI_SF32LB_USART_ENABLED
8+
select SERIAL_HAS_DRIVER
9+
select PINCTRL
10+
select CLOCK_CONTROL
11+
help
12+
This option enables the SiFli SF32LB UART driver.

drivers/serial/uart_sf32lb.c

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
/*
2+
* Copyright (c) Core Devices LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT sifli_sf32lb_usart
7+
8+
#include <zephyr/arch/cpu.h>
9+
#include <zephyr/device.h>
10+
#include <zephyr/devicetree.h>
11+
#include <zephyr/drivers/clock_control/sf32lb.h>
12+
#include <zephyr/drivers/pinctrl.h>
13+
#include <zephyr/drivers/uart.h>
14+
15+
#include <register.h>
16+
17+
#define UART_CR1 offsetof(USART_TypeDef, CR1)
18+
#define UART_CR2 offsetof(USART_TypeDef, CR2)
19+
#define UART_CR3 offsetof(USART_TypeDef, CR3)
20+
#define UART_BRR offsetof(USART_TypeDef, BRR)
21+
#define UART_ISR offsetof(USART_TypeDef, ISR)
22+
#define UART_ICR offsetof(USART_TypeDef, ICR)
23+
#define UART_RDR offsetof(USART_TypeDef, RDR)
24+
#define UART_TDR offsetof(USART_TypeDef, TDR)
25+
#define UART_MISCR offsetof(USART_TypeDef, MISCR)
26+
27+
#define UART_CR1_M_6B FIELD_PREP(USART_CR1_M_Msk, 0U)
28+
#define UART_CR1_M_7B FIELD_PREP(USART_CR1_M_Msk, 1U)
29+
#define UART_CR1_M_8B FIELD_PREP(USART_CR1_M_Msk, 2U)
30+
#define UART_CR1_M_9B FIELD_PREP(USART_CR1_M_Msk, 3U)
31+
32+
#define UART_CR2_STOP_1B FIELD_PREP(USART_CR2_STOP_Msk, 0U)
33+
#define UART_CR2_STOP_2B FIELD_PREP(USART_CR2_STOP_Msk, 1U)
34+
35+
/* minimal BRR: INT=1, FRAC=0 (0x10) */
36+
#define UART_BRR_MIN 0x10U
37+
38+
struct uart_sf32lb_config {
39+
uintptr_t base;
40+
const struct pinctrl_dev_config *pcfg;
41+
struct sf32lb_clock_dt_spec clock;
42+
struct uart_config uart_cfg;
43+
};
44+
45+
static int uart_sf32lb_configure(const struct device *dev, const struct uart_config *cfg)
46+
{
47+
const struct uart_sf32lb_config *config = dev->config;
48+
enum uart_config_data_bits data_bits = cfg->data_bits;
49+
uint32_t cr1, cr2, cr3, brr, miscr;
50+
51+
/* CR1: disable USART */
52+
cr1 = sys_read32(config->base + UART_CR1);
53+
cr1 &= ~USART_CR1_UE;
54+
sys_write32(cr1, config->base + UART_CR1);
55+
56+
/* CR1: data bits, parity, oversampling */
57+
cr1 &= ~(USART_CR1_M_Msk | USART_CR1_PCE_Msk | USART_CR1_PS_Msk | USART_CR1_OVER8_Msk);
58+
59+
/* data bits include parity bit */
60+
if (cfg->parity != UART_CFG_PARITY_NONE) {
61+
data_bits++;
62+
if (data_bits > UART_CFG_DATA_BITS_9) {
63+
return -ENOTSUP;
64+
}
65+
}
66+
67+
switch (data_bits) {
68+
case UART_CFG_DATA_BITS_6:
69+
cr1 |= UART_CR1_M_6B;
70+
break;
71+
case UART_CFG_DATA_BITS_7:
72+
cr1 |= UART_CR1_M_7B;
73+
break;
74+
case UART_CFG_DATA_BITS_8:
75+
cr1 |= UART_CR1_M_8B;
76+
break;
77+
case UART_CFG_DATA_BITS_9:
78+
cr1 |= UART_CR1_M_9B;
79+
break;
80+
default:
81+
return -ENOTSUP;
82+
}
83+
84+
switch (cfg->parity) {
85+
case UART_CFG_PARITY_NONE:
86+
break;
87+
case UART_CFG_PARITY_ODD:
88+
cr1 |= (USART_CR1_PCE | USART_CR1_PS);
89+
break;
90+
case UART_CFG_PARITY_EVEN:
91+
cr1 |= USART_CR1_PCE;
92+
break;
93+
default:
94+
return -ENOTSUP;
95+
}
96+
97+
sys_write32(cr1, config->base + UART_CR1);
98+
99+
/* CR2: stop bits */
100+
cr2 = sys_read32(config->base + UART_CR2);
101+
cr2 &= ~USART_CR2_STOP_Msk;
102+
103+
switch (cfg->stop_bits) {
104+
case UART_CFG_STOP_BITS_1:
105+
cr2 |= UART_CR2_STOP_1B;
106+
break;
107+
case UART_CFG_STOP_BITS_2:
108+
cr2 |= UART_CR2_STOP_2B;
109+
break;
110+
default:
111+
return -ENOTSUP;
112+
}
113+
114+
sys_write32(cr2, config->base + UART_CR2);
115+
116+
/* CR3: flow control */
117+
cr3 = sys_read32(config->base + UART_CR3);
118+
cr3 &= ~(USART_CR3_RTSE_Msk | USART_CR3_CTSE_Msk);
119+
120+
switch (cfg->flow_ctrl) {
121+
case UART_CFG_FLOW_CTRL_NONE:
122+
break;
123+
case UART_CFG_FLOW_CTRL_RTS_CTS:
124+
cr3 |= (USART_CR3_RTSE_Msk | USART_CR3_CTSE_Msk);
125+
break;
126+
default:
127+
return -ENOTSUP;
128+
}
129+
130+
sys_write32(cr3, config->base + UART_CR3);
131+
132+
/* enable USART */
133+
cr1 |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
134+
sys_write32(cr1, config->base + UART_CR1);
135+
136+
/* BRR: baudrate */
137+
miscr = sys_read32(config->base + UART_MISCR);
138+
miscr &= ~USART_MISCR_SMPLINI_Msk;
139+
140+
brr = 48000000UL / config->uart_cfg.baudrate;
141+
if (brr < UART_BRR_MIN) {
142+
cr1 |= USART_CR1_OVER8;
143+
sys_write32(cr1, config->base + UART_CR1);
144+
/* recalculate brr with reduced oversampling */
145+
brr = (48000000UL * 2U) / config->uart_cfg.baudrate;
146+
miscr |= FIELD_PREP(USART_MISCR_SMPLINI_Msk, 2U);
147+
} else {
148+
miscr |= FIELD_PREP(USART_MISCR_SMPLINI_Msk, 6U);
149+
}
150+
151+
sys_write32(miscr, config->base + UART_MISCR);
152+
sys_write32(brr, config->base + UART_BRR);
153+
154+
return 0;
155+
}
156+
157+
static int uart_sf32lb_poll_in(const struct device *dev, uint8_t *c)
158+
{
159+
const struct uart_sf32lb_config *config = dev->config;
160+
161+
if ((sys_read32(config->base + UART_ISR) & USART_ISR_RXNE) != 0U) {
162+
*c = sys_read32(config->base + UART_RDR) & 0xFFU;
163+
return 0;
164+
}
165+
166+
return -1;
167+
}
168+
169+
static void uart_sf32lb_poll_out(const struct device *dev, uint8_t c)
170+
{
171+
const struct uart_sf32lb_config *config = dev->config;
172+
173+
sys_write32(USART_ISR_TC, config->base + UART_ICR);
174+
sys_write8(c, config->base + UART_TDR);
175+
176+
while ((sys_read32(config->base + UART_ISR) & USART_ISR_TC) == 0U) {
177+
}
178+
}
179+
180+
static const struct uart_driver_api uart_sf32lb_api = {
181+
.poll_in = uart_sf32lb_poll_in,
182+
.poll_out = uart_sf32lb_poll_out,
183+
};
184+
185+
static int uart_sf32lb_init(const struct device *dev)
186+
{
187+
const struct uart_sf32lb_config *config = dev->config;
188+
int ret;
189+
190+
ret = pinctrl_apply_state(config->pcfg, PINCTRL_STATE_DEFAULT);
191+
if (ret < 0) {
192+
return ret;
193+
}
194+
195+
if (config->clock.dev != NULL) {
196+
if (!sf3232lb_clock_is_ready_dt(&config->clock)) {
197+
return -ENODEV;
198+
}
199+
200+
ret = sf32lb_clock_control_on_dt(&config->clock);
201+
if (ret < 0) {
202+
return ret;
203+
}
204+
}
205+
206+
ret = uart_sf32lb_configure(dev, &config->uart_cfg);
207+
if (ret < 0) {
208+
return ret;
209+
}
210+
211+
return 0;
212+
}
213+
214+
#define SF32LB_UART_DEFINE(index) \
215+
PINCTRL_DT_INST_DEFINE(index); \
216+
\
217+
static const struct uart_sf32lb_config uart_sf32lb_cfg_##index = { \
218+
.base = DT_INST_REG_ADDR(index), \
219+
.clock = SF32LB_CLOCK_DT_INST_SPEC_GET_OR(index, {}), \
220+
.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
221+
.uart_cfg = \
222+
{ \
223+
.baudrate = DT_INST_PROP(index, current_speed), \
224+
.parity = \
225+
DT_INST_ENUM_IDX_OR(index, parity, UART_CFG_PARITY_NONE), \
226+
.stop_bits = DT_INST_ENUM_IDX_OR(index, stop_bits, \
227+
UART_CFG_STOP_BITS_1), \
228+
.data_bits = DT_INST_ENUM_IDX_OR(index, data_bits, \
229+
UART_CFG_DATA_BITS_8), \
230+
.flow_ctrl = DT_INST_PROP(index, hw_flow_control) \
231+
? UART_CFG_FLOW_CTRL_RTS_CTS \
232+
: UART_CFG_FLOW_CTRL_NONE, \
233+
}, \
234+
}; \
235+
\
236+
DEVICE_DT_INST_DEFINE(index, uart_sf32lb_init, NULL, NULL, &uart_sf32lb_cfg_##index, \
237+
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, &uart_sf32lb_api);
238+
239+
DT_INST_FOREACH_STATUS_OKAY(SF32LB_UART_DEFINE)

0 commit comments

Comments
 (0)