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) 2010, 2012-2015 Wind River Systems, Inc.
* Copyright (c) 2020 Intel Corp. * Copyright (c) 2020-2022 Intel Corp.
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -28,6 +28,7 @@
#include <zephyr/toolchain.h> #include <zephyr/toolchain.h>
#include <zephyr/linker/sections.h> #include <zephyr/linker/sections.h>
#include <zephyr/drivers/uart.h> #include <zephyr/drivers/uart.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/pm/policy.h> #include <zephyr/pm/policy.h>
#include <zephyr/sys/sys_io.h> #include <zephyr/sys/sys_io.h>
#include <zephyr/spinlock.h> #include <zephyr/spinlock.h>
@ -225,6 +226,8 @@ struct uart_ns16550_device_config {
uint32_t port; uint32_t port;
#endif #endif
uint32_t sys_clk_freq; 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) #if defined(CONFIG_UART_INTERRUPT_DRIVEN) || defined(CONFIG_UART_ASYNC_API)
uart_irq_config_func_t irq_config_func; uart_irq_config_func_t irq_config_func;
#endif #endif
@ -283,19 +286,18 @@ static inline uintptr_t get_port(const struct device *dev)
#endif #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; struct uart_ns16550_dev_data * const dev_data = dev->data;
uint32_t divisor; /* baud rate divisor */ uint32_t divisor; /* baud rate divisor */
uint8_t lcr_cache; 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 * 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; / baud_rate) >> 4;
/* set the DLAB to access the baud rate divisor registers */ /* 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; struct uart_ns16550_dev_data * const dev_data = dev->data;
const struct uart_ns16550_device_config * const dev_cfg = dev->config; const struct uart_ns16550_device_config * const dev_cfg = dev->config;
uint8_t mdc = 0U; uint8_t mdc = 0U;
uint32_t pclk = 0U;
/* temp for return value if error occurs in this locked region */ /* temp for return value if error occurs in this locked region */
int ret = 0; int ret = 0;
@ -367,7 +370,23 @@ static int uart_ns16550_configure(const struct device *dev,
} }
#endif #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() */ /* Local structure to hold temporary values to pass to OUTBYTE() */
struct uart_config uart_cfg; 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); \ UART_NS16550_IRQ_FUNC_DECLARE(n); \
static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \ static const struct uart_ns16550_device_config uart_ns16550_dev_cfg_##n = { \
DEV_CONFIG_REG_INIT(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_IRQ_FUNC_INIT(n) \
DEV_CONFIG_PCP_INIT(n) \ DEV_CONFIG_PCP_INIT(n) \
.reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \ .reg_interval = (1 << DT_INST_PROP(n, reg_shift)), \

View file

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