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)), \

View file

@ -1,12 +1,13 @@
/*
* SPDX-License-Identifier: Apache-2.0
*
* Copyright (C) 2021, Intel Corporation
* Copyright (C) 2021-2022, Intel Corporation
*
*/
#include <arm64/armv8-a.dtsi>
#include <zephyr/dt-bindings/interrupt-controller/arm-gic.h>
#include <zephyr/dt-bindings/clock/intel_socfpga_clock.h>
/ {
cpus {
@ -70,7 +71,7 @@
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL
IRQ_DEFAULT_PRIORITY>;
interrupt-names = "irq_0";
clock-frequency = <100000000>;
clocks = <&clock INTEL_SOCFPGA_CLOCK_UART>;
label = "uart_0";
status = "disabled";
};