Skip to content

Commit 62396ed

Browse files
committed
drivers: added serial driver for MSPM0
added the Serial (uart) driver for MSPM0 family Signed-off-by: Jackson Farley <[email protected]>
1 parent 3c67023 commit 62396ed

File tree

6 files changed

+410
-0
lines changed

6 files changed

+410
-0
lines changed

drivers/serial/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ zephyr_library_sources_ifdef(CONFIG_UART_MCUX_LPUART uart_mcux_lpuart.c)
2424
zephyr_library_sources_ifdef(CONFIG_UART_MCUX_LPSCI uart_mcux_lpsci.c)
2525
zephyr_library_sources_ifdef(CONFIG_UART_MIV uart_miv.c)
2626
zephyr_library_sources_ifdef(CONFIG_UART_MSP432P4XX uart_msp432p4xx.c)
27+
zephyr_library_sources_ifdef(CONFIG_UART_MSPM0 uart_mspm0.c)
2728
zephyr_library_sources_ifdef(CONFIG_UART_NS16550 uart_ns16550.c)
2829
zephyr_library_sources_ifdef(CONFIG_UART_NRFX_UART uart_nrfx_uart.c)
2930
if (CONFIG_UART_NRFX_UARTE)

drivers/serial/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ source "drivers/serial/Kconfig.leuart_gecko"
200200

201201
source "drivers/serial/Kconfig.msp432p4xx"
202202

203+
source "drivers/serial/Kconfig.mspm0"
204+
203205
source "drivers/serial/Kconfig.numicro"
204206

205207
source "drivers/serial/Kconfig.sam0"

drivers/serial/Kconfig.mspm0

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
# Copyright (c) 2024 Texas Instruments
3+
4+
config UART_MSPM0
5+
bool "MSPM0 UART driver"
6+
default y
7+
depends on DT_HAS_TI_MSPM0_UART_ENABLED
8+
select SERIAL_HAS_DRIVER
9+
select SERIAL_SUPPORT_INTERRUPT
10+
help
11+
This option enables the TI MSPM0 UART driver.

drivers/serial/uart_mspm0.c

Lines changed: 295 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,295 @@
1+
/*
2+
* Copyright (c) 2024 Texas Instruments
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT ti_mspm0_uart
8+
9+
/* Zephyr includes */
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/drivers/pinctrl.h>
12+
#include <zephyr/drivers/uart.h>
13+
#include <zephyr/irq.h>
14+
#include <soc.h>
15+
16+
/* Defines for UART0 */
17+
#define UART_0_IBRD_33_kHZ_9600_BAUD (1)
18+
#define UART_0_FBRD_33_kHZ_9600_BAUD (9)
19+
20+
/* Driverlib includes */
21+
#include <ti/driverlib/dl_uart_main.h>
22+
23+
struct uart_mspm0_config {
24+
UART_Regs *regs;
25+
uint32_t clock_frequency;
26+
uint32_t current_speed;
27+
const struct pinctrl_dev_config *pinctrl;
28+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
29+
uart_irq_config_func_t irq_config_func;
30+
#endif
31+
};
32+
33+
struct uart_mspm0_data {
34+
/* UART clock structure */
35+
DL_UART_Main_ClockConfig UART_ClockConfig;
36+
/* UART config structure */
37+
DL_UART_Main_Config UART_Config;
38+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
39+
uart_irq_callback_user_data_t cb; /* Callback function pointer */
40+
void *cb_data; /* Callback function arg */
41+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
42+
};
43+
44+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
45+
static void uart_mspm0_isr(const struct device *dev);
46+
#define MSPM0_INTERRUPT_CALLBACK_FN(index) .cb = NULL,
47+
#else
48+
#define MSPM0_INTERRUPT_CALLBACK_FN(index)
49+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
50+
51+
static int uart_mspm0_init(const struct device *dev)
52+
{
53+
const struct uart_mspm0_config *config = dev->config;
54+
struct uart_mspm0_data *data = dev->data;
55+
int ret;
56+
57+
/* Reset power */
58+
DL_UART_Main_reset(config->regs);
59+
DL_UART_Main_enablePower(config->regs);
60+
delay_cycles(POWER_STARTUP_DELAY);
61+
62+
/* Init UART pins */
63+
ret = pinctrl_apply_state(config->pinctrl, PINCTRL_STATE_DEFAULT);
64+
if (ret < 0) {
65+
return ret;
66+
}
67+
68+
/* Set UART configs */
69+
DL_UART_Main_setClockConfig(config->regs,
70+
(DL_UART_Main_ClockConfig *)&data->UART_ClockConfig);
71+
DL_UART_Main_init(config->regs, (DL_UART_Main_Config *)&data->UART_Config);
72+
73+
/*
74+
* Configure baud rate by setting oversampling and baud rate divisor
75+
* from the device tree data current-speed
76+
*/
77+
DL_UART_Main_configBaudRate(config->regs, 32000000, config->current_speed);
78+
79+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
80+
config->irq_config_func(dev);
81+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
82+
83+
/* Enable UART */
84+
DL_UART_Main_enable(config->regs);
85+
86+
return 0;
87+
}
88+
89+
static int uart_mspm0_poll_in(const struct device *dev, unsigned char *c)
90+
{
91+
const struct uart_mspm0_config *config = dev->config;
92+
93+
return (DL_UART_Main_receiveDataCheck(config->regs, c)) ? 0 : -1;
94+
}
95+
96+
static void uart_mspm0_poll_out(const struct device *dev, unsigned char c)
97+
{
98+
const struct uart_mspm0_config *config = dev->config;
99+
100+
DL_UART_Main_transmitDataBlocking(config->regs, c);
101+
}
102+
103+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
104+
105+
#define UART_MSPM0_TX_INTERRUPTS (DL_UART_MAIN_INTERRUPT_TX | DL_UART_MAIN_INTERRUPT_EOT_DONE)
106+
#define UART_MSPM0_RX_INTERRUPTS (DL_UART_MAIN_INTERRUPT_RX)
107+
108+
static int uart_mspm0_fifo_fill(const struct device *dev, const uint8_t *tx_data, int size)
109+
{
110+
const struct uart_mspm0_config *config = dev->config;
111+
112+
return (int)DL_UART_Main_fillTXFIFO(config->regs, (uint8_t *)tx_data, size);
113+
}
114+
115+
static int uart_mspm0_fifo_read(const struct device *dev, uint8_t *rx_data, const int size)
116+
{
117+
const struct uart_mspm0_config *config = dev->config;
118+
119+
return (int)DL_UART_Main_drainRXFIFO(config->regs, rx_data, size);
120+
}
121+
122+
static void uart_mspm0_irq_tx_enable(const struct device *dev)
123+
{
124+
const struct uart_mspm0_config *config = dev->config;
125+
126+
DL_UART_Main_enableInterrupt(config->regs, UART_MSPM0_TX_INTERRUPTS);
127+
}
128+
129+
static void uart_mspm0_irq_tx_disable(const struct device *dev)
130+
{
131+
const struct uart_mspm0_config *config = dev->config;
132+
133+
DL_UART_Main_disableInterrupt(config->regs, UART_MSPM0_TX_INTERRUPTS);
134+
}
135+
136+
static int uart_mspm0_irq_tx_ready(const struct device *dev)
137+
{
138+
const struct uart_mspm0_config *config = dev->config;
139+
140+
return (DL_UART_Main_getEnabledInterruptStatus(
141+
config->regs, DL_UART_MAIN_INTERRUPT_TX)) ? 0 : 1;
142+
}
143+
144+
static void uart_mspm0_irq_rx_enable(const struct device *dev)
145+
{
146+
const struct uart_mspm0_config *config = dev->config;
147+
148+
DL_UART_Main_enableInterrupt(config->regs, UART_MSPM0_RX_INTERRUPTS);
149+
}
150+
151+
static void uart_mspm0_irq_rx_disable(const struct device *dev)
152+
{
153+
const struct uart_mspm0_config *config = dev->config;
154+
155+
DL_UART_Main_disableInterrupt(config->regs, UART_MSPM0_RX_INTERRUPTS);
156+
}
157+
158+
static int uart_mspm0_irq_tx_complete(const struct device *dev)
159+
{
160+
const struct uart_mspm0_config *config = dev->config;
161+
162+
return (DL_UART_Main_isTXFIFOEmpty(config->regs)) ? 1 : 0;
163+
}
164+
165+
static int uart_mspm0_irq_rx_ready(const struct device *dev)
166+
{
167+
const struct uart_mspm0_config *config = dev->config;
168+
169+
return (DL_UART_Main_getEnabledInterruptStatus(
170+
config->regs, UART_MSPM0_RX_INTERRUPTS)) ? 1 : 0;
171+
}
172+
173+
static int uart_mspm0_irq_is_pending(const struct device *dev)
174+
{
175+
const struct uart_mspm0_config *config = dev->config;
176+
177+
return (DL_UART_Main_getEnabledInterruptStatus(config->regs,
178+
UART_MSPM0_RX_INTERRUPTS | UART_MSPM0_TX_INTERRUPTS)) ? 1 : 0;
179+
}
180+
181+
static int uart_mspm0_irq_update(const struct device *dev)
182+
{
183+
ARG_UNUSED(dev);
184+
return 1;
185+
}
186+
187+
static void uart_mspm0_irq_callback_set(const struct device *dev,
188+
uart_irq_callback_user_data_t cb, void *cb_data)
189+
{
190+
struct uart_mspm0_data *const dev_data = dev->data;
191+
192+
/* Set callback function and data */
193+
dev_data->cb = cb;
194+
dev_data->cb_data = cb_data;
195+
}
196+
197+
/**
198+
* @brief Interrupt service routine.
199+
*
200+
* This simply calls the callback function, if one exists.
201+
*
202+
* @param arg Argument to ISR.
203+
*/
204+
static void uart_mspm0_isr(const struct device *dev)
205+
{
206+
const struct uart_mspm0_config *config = dev->config;
207+
struct uart_mspm0_data *const dev_data = dev->data;
208+
209+
int int_status = DL_UART_Main_getEnabledInterruptStatus(config->regs,
210+
UART_MSPM0_RX_INTERRUPTS | UART_MSPM0_TX_INTERRUPTS);
211+
212+
/* Perform callback if defined */
213+
if (dev_data->cb) {
214+
dev_data->cb(dev, dev_data->cb_data);
215+
}
216+
217+
/*
218+
* Clear interrupts only after cb called, as Zephyr UART clients expect
219+
* to check interrupt status during the callback.
220+
*/
221+
222+
DL_UART_Main_clearInterruptStatus(config->regs, int_status);
223+
224+
}
225+
226+
#define MSP_UART_IRQ_REGISTER(index) \
227+
static void uart_mspm0_##index##_irq_register(const struct device *dev) \
228+
{\
229+
IRQ_CONNECT(DT_INST_IRQN(index), DT_INST_IRQ(index, priority), \
230+
uart_mspm0_isr, DEVICE_DT_INST_GET(index), 0); \
231+
irq_enable(DT_INST_IRQN(index)); \
232+
}
233+
234+
#else
235+
236+
#define MSP_UART_IRQ_REGISTER(index)
237+
238+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
239+
240+
static const struct uart_driver_api uart_mspm0_driver_api = {
241+
.poll_in = uart_mspm0_poll_in,
242+
.poll_out = uart_mspm0_poll_out,
243+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
244+
.fifo_fill = uart_mspm0_fifo_fill,
245+
.fifo_read = uart_mspm0_fifo_read,
246+
.irq_tx_enable = uart_mspm0_irq_tx_enable,
247+
.irq_tx_disable = uart_mspm0_irq_tx_disable,
248+
.irq_tx_ready = uart_mspm0_irq_tx_ready,
249+
.irq_rx_enable = uart_mspm0_irq_rx_enable,
250+
.irq_rx_disable = uart_mspm0_irq_rx_disable,
251+
.irq_tx_complete = uart_mspm0_irq_tx_complete,
252+
.irq_rx_ready = uart_mspm0_irq_rx_ready,
253+
.irq_is_pending = uart_mspm0_irq_is_pending,
254+
.irq_update = uart_mspm0_irq_update,
255+
.irq_callback_set = uart_mspm0_irq_callback_set,
256+
#endif /* CONFIG_UART_INTERRUPT_DRIVEN */
257+
};
258+
259+
#define MSPM0_UART_INIT_FN(index) \
260+
\
261+
PINCTRL_DT_INST_DEFINE(index); \
262+
\
263+
MSP_UART_IRQ_REGISTER(index) \
264+
\
265+
static const struct uart_mspm0_config uart_mspm0_cfg_##index = { \
266+
.regs = (UART_Regs *)DT_INST_REG_ADDR(index), \
267+
.current_speed = DT_INST_PROP(index, current_speed),\
268+
.pinctrl = PINCTRL_DT_INST_DEV_CONFIG_GET(index), \
269+
IF_ENABLED(CONFIG_UART_INTERRUPT_DRIVEN, \
270+
(.irq_config_func = uart_mspm0_##index##_irq_register,)) \
271+
}; \
272+
\
273+
static struct uart_mspm0_data uart_mspm0_data_##index = { \
274+
.UART_ClockConfig = { \
275+
.clockSel = DL_UART_MAIN_CLOCK_BUSCLK, \
276+
.divideRatio = DL_UART_MAIN_CLOCK_DIVIDE_RATIO_1 \
277+
}, \
278+
.UART_Config = \
279+
{ \
280+
.mode = DL_UART_MAIN_MODE_NORMAL, \
281+
.direction = DL_UART_MAIN_DIRECTION_TX_RX, \
282+
.flowControl = DL_UART_MAIN_FLOW_CONTROL_NONE, \
283+
.parity = DL_UART_MAIN_PARITY_NONE, \
284+
.wordLength = DL_UART_MAIN_WORD_LENGTH_8_BITS, \
285+
.stopBits = DL_UART_MAIN_STOP_BITS_ONE, \
286+
}, \
287+
MSPM0_INTERRUPT_CALLBACK_FN(index) \
288+
}; \
289+
\
290+
DEVICE_DT_INST_DEFINE(index, &uart_mspm0_init, NULL, \
291+
&uart_mspm0_data_##index, &uart_mspm0_cfg_##index, \
292+
PRE_KERNEL_1, CONFIG_SERIAL_INIT_PRIORITY, \
293+
&uart_mspm0_driver_api);
294+
295+
DT_INST_FOREACH_STATUS_OKAY(MSPM0_UART_INIT_FN)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
description: TI MSPM0 UART
2+
3+
compatible: "ti,mspm0-uart"
4+
5+
include: [uart-controller.yaml, pinctrl-device.yaml, base.yaml]
6+
7+
properties:
8+
reg:
9+
required: true
10+
11+
interrupts:
12+
required: true
13+
14+
pinctrl-0:
15+
required: true
16+
17+
pinctrl-names:
18+
required: true

0 commit comments

Comments
 (0)