drivers: uart_pl011: Implemented runtime configure
Implemented runtime configure functions for the driver.
Signed-off-by: Lukas Gehreke <lk.gehreke@gmail.com>
diff --git a/drivers/serial/uart_pl011.c b/drivers/serial/uart_pl011.c
index a480f89..3510fe2 100644
--- a/drivers/serial/uart_pl011.c
+++ b/drivers/serial/uart_pl011.c
@@ -9,6 +9,7 @@
#define DT_DRV_COMPAT arm_pl011
#define SBSA_COMPAT arm_sbsa_uart
+#include <string.h>
#include <zephyr/kernel.h>
#include <zephyr/arch/cpu.h>
#include <zephyr/init.h>
@@ -44,7 +45,7 @@
/* Device data structure */
struct pl011_data {
DEVICE_MMIO_RAM;
- uint32_t baud_rate; /* Baud rate */
+ struct uart_config uart_cfg;
bool sbsa; /* SBSA mode */
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
volatile bool sw_call_txdrdy;
@@ -139,6 +140,115 @@
get_uart(dev)->dr = (uint32_t)c;
}
+static int pl011_runtime_configure_internal(const struct device *dev,
+ const struct uart_config *cfg,
+ bool disable)
+{
+ const struct pl011_config *config = dev->config;
+ struct pl011_data *data = dev->data;
+ uint32_t lcrh;
+ int ret = -ENOTSUP;
+
+ if (data->sbsa) {
+ goto out;
+ }
+
+ if (disable) {
+ pl011_disable(dev);
+ pl011_disable_fifo(dev);
+ }
+
+ lcrh = get_uart(dev)->lcr_h & ~(PL011_LCRH_FORMAT_MASK | PL011_LCRH_STP2);
+
+ switch (cfg->parity) {
+ case UART_CFG_PARITY_NONE:
+ lcrh &= ~(BIT(1) | BIT(2));
+ break;
+ case UART_CFG_PARITY_ODD:
+ lcrh |= PL011_LCRH_PARITY_ODD;
+ break;
+ case UART_CFG_PARITY_EVEN:
+ lcrh |= PL011_LCRH_PARTIY_EVEN;
+ break;
+ default:
+ goto enable;
+ }
+
+ switch (cfg->stop_bits) {
+ case UART_CFG_STOP_BITS_1:
+ lcrh &= ~(PL011_LCRH_STP2);
+ break;
+ case UART_CFG_STOP_BITS_2:
+ lcrh |= PL011_LCRH_STP2;
+ break;
+ default:
+ goto enable;
+ }
+
+ switch (cfg->data_bits) {
+ case UART_CFG_DATA_BITS_5:
+ lcrh |= PL011_LCRH_WLEN_SIZE(5) << PL011_LCRH_WLEN_SHIFT;
+ break;
+ case UART_CFG_DATA_BITS_6:
+ lcrh |= PL011_LCRH_WLEN_SIZE(6) << PL011_LCRH_WLEN_SHIFT;
+ break;
+ case UART_CFG_DATA_BITS_7:
+ lcrh |= PL011_LCRH_WLEN_SIZE(7) << PL011_LCRH_WLEN_SHIFT;
+ break;
+ case UART_CFG_DATA_BITS_8:
+ lcrh |= PL011_LCRH_WLEN_SIZE(8) << PL011_LCRH_WLEN_SHIFT;
+ break;
+ default:
+ goto enable;
+ }
+
+ switch (cfg->flow_ctrl) {
+ case UART_CFG_FLOW_CTRL_NONE:
+ break;
+ default:
+ goto enable;
+ }
+
+ /* Set baud rate */
+ ret = pl011_set_baudrate(dev, config->sys_clk_freq, cfg->baudrate);
+ if (ret != 0) {
+ goto enable;
+ }
+
+ /* Update settings */
+ get_uart(dev)->lcr_h = lcrh;
+
+ memcpy(&data->uart_cfg, cfg, sizeof(data->uart_cfg));
+
+enable:
+ if (disable) {
+ pl011_enable_fifo(dev);
+ pl011_enable(dev);
+ }
+
+out:
+ return ret;
+}
+
+#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
+
+static int pl011_runtime_configure(const struct device *dev,
+ const struct uart_config *cfg)
+{
+ return pl011_runtime_configure_internal(dev, cfg, true);
+}
+
+static int pl011_runtime_config_get(const struct device *dev,
+ struct uart_config *cfg)
+{
+ struct pl011_data *data = dev->data;
+
+ *cfg = data->uart_cfg;
+ return 0;
+}
+
+#endif /* CONFIG_UART_USE_RUNTIME_CONFIGURE */
+
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
static int pl011_fifo_fill(const struct device *dev,
const uint8_t *tx_data, int len)
@@ -268,6 +378,10 @@
static const struct uart_driver_api pl011_driver_api = {
.poll_in = pl011_poll_in,
.poll_out = pl011_poll_out,
+#ifdef CONFIG_UART_USE_RUNTIME_CONFIGURE
+ .configure = pl011_runtime_configure,
+ .config_get = pl011_runtime_config_get,
+#endif
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
.fifo_fill = pl011_fifo_fill,
.fifo_read = pl011_fifo_read,
@@ -291,7 +405,6 @@
const struct pl011_config *config = dev->config;
struct pl011_data *data = dev->data;
int ret;
- uint32_t lcrh;
DEVICE_MMIO_MAP(dev, K_MEM_CACHE_NONE);
@@ -324,18 +437,7 @@
}
}
- /* Set baud rate */
- ret = pl011_set_baudrate(dev, config->sys_clk_freq,
- data->baud_rate);
- if (ret != 0) {
- return ret;
- }
-
- /* Setting the default character format */
- lcrh = get_uart(dev)->lcr_h & ~(PL011_LCRH_FORMAT_MASK);
- lcrh &= ~(BIT(0) | BIT(7));
- lcrh |= PL011_LCRH_WLEN_SIZE(8) << PL011_LCRH_WLEN_SHIFT;
- get_uart(dev)->lcr_h = lcrh;
+ pl011_runtime_configure_internal(dev, &data->uart_cfg, false);
/* Setting transmit and receive interrupt FIFO level */
get_uart(dev)->ifls = FIELD_PREP(PL011_IFLS_TXIFLSEL_M, TXIFLSEL_1_8_FULL)
@@ -439,7 +541,13 @@
PL011_CONFIG_PORT(n) \
\
static struct pl011_data pl011_data_port_##n = { \
- .baud_rate = DT_INST_PROP(n, current_speed), \
+ .uart_cfg = { \
+ .baudrate = DT_INST_PROP(n, current_speed), \
+ .parity = UART_CFG_PARITY_NONE, \
+ .stop_bits = UART_CFG_STOP_BITS_1, \
+ .data_bits = UART_CFG_DATA_BITS_8, \
+ .flow_ctrl = UART_CFG_FLOW_CTRL_NONE, \
+ }, \
}; \
\
DEVICE_DT_INST_DEFINE(n, &pl011_init, \