drivers: serial: Uart ns16550 get clock frequency from clock manager

This patch is to enhance the uart ns16550 driver to get clock frequency
from clock manager or devicetree if clock_frequency is defined.

Signed-off-by: Teik Heng Chong <teik.heng.chong@intel.com>
This commit is contained in:
Teik Heng Chong 2022-07-02 16:34:04 +00:00 committed by Fabio Baltieri
commit f551c29576
2 changed files with 40 additions and 10 deletions

View file

@ -4,7 +4,7 @@
/*
* Copyright (c) 2010, 2012-2015 Wind River Systems, Inc.
* Copyright (c) 2020 Intel Corp.
* Copyright (c) 2020-2022 Intel Corp.
*
* SPDX-License-Identifier: Apache-2.0
*/
@ -28,6 +28,7 @@
#include <zephyr/toolchain.h>
#include <zephyr/linker/sections.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/pm/policy.h>
#include <zephyr/sys/sys_io.h>
#include <zephyr/spinlock.h>
@ -225,6 +226,8 @@ struct uart_ns16550_device_config {
uint32_t port;
#endif
uint32_t sys_clk_freq;
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
#if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API)
uart_irq_config_func_t irq_config_func;
#endif
@ -283,19 +286,18 @@ static inline uintptr_t get_port(const struct device *dev)
#endif
}
static void set_baud_rate(const struct device *dev, uint32_t baud_rate)
static void set_baud_rate(const struct device *dev, uint32_t baud_rate, uint32_t pclk)
{
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
struct uart_ns16550_dev_data * const dev_data = dev->data;
uint32_t divisor; /* baud rate divisor */
uint8_t lcr_cache;
if ((baud_rate != 0U) && (dev_cfg->sys_clk_freq != 0U)) {
if ((baud_rate != 0U) && (pclk != 0U)) {
/*
* calculate baud rate divisor. a variant of
* (uint32_t)(dev_cfg->sys_clk_freq / (16.0 * baud_rate) + 0.5)
* (uint32_t)(pclk / (16.0 * baud_rate) + 0.5)
*/
divisor = ((dev_cfg->sys_clk_freq + (baud_rate << 3))
divisor = ((pclk + (baud_rate << 3))
/ baud_rate) >> 4;
/* set the DLAB to access the baud rate divisor registers */
@ -317,6 +319,7 @@ static int uart_ns16550_configure(const struct device *dev,
struct uart_ns16550_dev_data * const dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config;
uint8_t mdc = 0U;
uint32_t pclk = 0U;
/* temp for return value if error occurs in this locked region */
int ret = 0;
@ -367,7 +370,23 @@ static int uart_ns16550_configure(const struct device *dev,
}
#endif
set_baud_rate(dev, cfg->baudrate);
/*
* set clock frequency from clock_frequency property if valid,
* otherwise, get clock frequency from clock manager
*/
if (dev_cfg->sys_clk_freq != 0U) {
pclk = dev_cfg->sys_clk_freq;
} else {
if (dev_cfg->clock_dev == NULL) {
ret = -EINVAL;
goto out;
}
clock_control_get_rate(dev_cfg->clock_dev, dev_cfg->clock_subsys,
&pclk);
}
set_baud_rate(dev, cfg->baudrate, pclk);
/* Local structure to hold temporary values to pass to OUTBYTE() */
struct uart_config uart_cfg;
@ -1111,7 +1130,17 @@ static const struct uart_driver_api uart_ns16550_driver_api = {
UART_NS16550_IRQ_FUNC_DECLARE(n); \
static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \
DEV_CONFIG_REG_INIT(n) \
.sys_clk_freq = DT_INST_PROP(n, clock_frequency), \
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, clock_frequency), ( \
.sys_clk_freq = DT_INST_PROP(n, clock_frequency), \
.clock_dev = NULL, \
.clock_subsys = NULL, \
), ( \
.sys_clk_freq = 0, \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
.clock_subsys = (clock_control_subsys_t) DT_INST_PHA(\
0, clocks, clkid), \
) \
) \
DEV_CONFIG_IRQ_FUNC_INIT(n) \
DEV_CONFIG_PCP_INIT(n) \
.reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \