From 45df8963f145127acc1f54dfb84eee6b8fa2ce91 Mon Sep 17 00:00:00 2001 From: Sadik Ozer Date: Fri, 13 Oct 2023 16:04:13 +0300 Subject: [PATCH] drivers: Add MAX32690 clock control driver Clock control for MAX32690 Co-authored-by: Okan Sahin Signed-off-by: Sadik Ozer --- drivers/clock_control/CMakeLists.txt | 1 + drivers/clock_control/Kconfig | 2 + drivers/clock_control/Kconfig.max32 | 9 + drivers/clock_control/clock_control_max32.c | 158 ++++++++++++++++++ dts/bindings/clock/adi,max32-gcr.yaml | 36 ++++ .../clock_control/adi_max32_clock_control.h | 98 +++++++++++ .../dt-bindings/clock/adi_max32_clock.h | 25 +++ 7 files changed, 329 insertions(+) create mode 100644 drivers/clock_control/Kconfig.max32 create mode 100644 drivers/clock_control/clock_control_max32.c create mode 100644 dts/bindings/clock/adi,max32-gcr.yaml create mode 100644 include/zephyr/drivers/clock_control/adi_max32_clock_control.h create mode 100644 include/zephyr/dt-bindings/clock/adi_max32_clock.h diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 596b07676e0..4cbd3ac47d6 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -76,3 +76,4 @@ if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) endif() zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_AST10X0 clock_control_ast10x0.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MAX32 clock_control_max32.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index b0c6cf8de48..b1b64f4a3ca 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -82,6 +82,8 @@ source "drivers/clock_control/Kconfig.agilex5" source "drivers/clock_control/Kconfig.renesas_ra" +source "drivers/clock_control/Kconfig.max32" + source "drivers/clock_control/Kconfig.ambiq" source "drivers/clock_control/Kconfig.pwm" diff --git a/drivers/clock_control/Kconfig.max32 b/drivers/clock_control/Kconfig.max32 new file mode 100644 index 00000000000..30f8d9fda7a --- /dev/null +++ b/drivers/clock_control/Kconfig.max32 @@ -0,0 +1,9 @@ +# Copyright (c) 2023-2024 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_MAX32 + bool "MAX32 Clock Control Driver" + default y + depends on DT_HAS_ADI_MAX32_GCR_ENABLED + help + Enable clock control support for Analog Devices MAX32xxx/MAX78xxx SoC series. diff --git a/drivers/clock_control/clock_control_max32.c b/drivers/clock_control/clock_control_max32.c new file mode 100644 index 00000000000..2cbed41bd23 --- /dev/null +++ b/drivers/clock_control/clock_control_max32.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2023-2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include + +#define DT_DRV_COMPAT adi_max32_gcr + +static inline int api_on(const struct device *dev, clock_control_subsys_t clkcfg) +{ + ARG_UNUSED(dev); + struct max32_perclk *perclk = (struct max32_perclk *)(clkcfg); + + switch (perclk->bus) { + case ADI_MAX32_CLOCK_BUS0: + MXC_SYS_ClockEnable((mxc_sys_periph_clock_t)perclk->bit); + break; + case ADI_MAX32_CLOCK_BUS1: + MXC_SYS_ClockEnable((mxc_sys_periph_clock_t)(perclk->bit + 32)); + break; + case ADI_MAX32_CLOCK_BUS2: + MXC_SYS_ClockEnable((mxc_sys_periph_clock_t)(perclk->bit + 64)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static inline int api_off(const struct device *dev, clock_control_subsys_t clkcfg) +{ + ARG_UNUSED(dev); + struct max32_perclk *perclk = (struct max32_perclk *)(clkcfg); + + switch (perclk->bus) { + case ADI_MAX32_CLOCK_BUS0: + MXC_SYS_ClockDisable((mxc_sys_periph_clock_t)perclk->bit); + break; + case ADI_MAX32_CLOCK_BUS1: + MXC_SYS_ClockDisable((mxc_sys_periph_clock_t)(perclk->bit + 32)); + break; + case ADI_MAX32_CLOCK_BUS2: + MXC_SYS_ClockDisable((mxc_sys_periph_clock_t)(perclk->bit + 64)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int api_get_rate(const struct device *dev, clock_control_subsys_t clkcfg, uint32_t *rate) +{ + ARG_UNUSED(dev); + struct max32_perclk *perclk = (struct max32_perclk *)(clkcfg); + + switch (perclk->clk_src) { + case ADI_MAX32_PRPH_CLK_SRC_PCLK: + *rate = ADI_MAX32_PCLK_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_EXTCLK: + *rate = ADI_MAX32_CLK_EXTCLK_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_IBRO: + *rate = ADI_MAX32_CLK_IBRO_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_ERFO: + *rate = ADI_MAX32_CLK_ERFO_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_ERTCO: + *rate = ADI_MAX32_CLK_ERTCO_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_INRO: + *rate = ADI_MAX32_CLK_INRO_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_ISO: + *rate = ADI_MAX32_CLK_ISO_FREQ; + break; + case ADI_MAX32_PRPH_CLK_SRC_IBRO_DIV8: + *rate = ADI_MAX32_CLK_IBRO_FREQ / 8; + break; + default: + *rate = 0U; + /* Invalid parameters */ + return -EINVAL; + } + + return 0; +} + +static const struct clock_control_driver_api max32_clkctrl_api = { + .on = api_on, + .off = api_off, + .get_rate = api_get_rate, +}; + +static void setup_fixed_clocks(void) +{ +#if DT_NODE_HAS_COMPAT(DT_NODELABEL(clk_extclk), fixed_clock) + MXC_SYS_ClockSourceDisable(ADI_MAX32_CLK_EXTCLK); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_ipo), okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IPO); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_erfo), okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ERFO); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_ibro), okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_IBRO); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_iso), okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ISO); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_inro), okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_INRO); +#endif + +#if DT_NODE_HAS_STATUS(DT_NODELABEL(clk_ertco), okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_ERTCO); +#endif + +/* Some device does not support external clock */ +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(clk_extclk), fixed_clock, okay) + MXC_SYS_ClockSourceEnable(ADI_MAX32_CLK_EXTCLK); +#endif +} + +static int max32_clkctrl_init(const struct device *dev) +{ + ARG_UNUSED(dev); + + /* Setup fixed clocks if enabled */ + setup_fixed_clocks(); + + /* Setup device clock source */ + MXC_SYS_Clock_Select(ADI_MAX32_SYSCLK_SRC); + +#if DT_NODE_HAS_PROP(DT_NODELABEL(gcr), sysclk_prescaler) + /* Setup divider */ + Wrap_MXC_SYS_SetClockDiv(sysclk_prescaler(ADI_MAX32_SYSCLK_PRESCALER)); +#endif + + return 0; +} + +DEVICE_DT_INST_DEFINE(0, max32_clkctrl_init, NULL, NULL, NULL, PRE_KERNEL_1, + CONFIG_CLOCK_CONTROL_INIT_PRIORITY, &max32_clkctrl_api); diff --git a/dts/bindings/clock/adi,max32-gcr.yaml b/dts/bindings/clock/adi,max32-gcr.yaml new file mode 100644 index 00000000000..be804954229 --- /dev/null +++ b/dts/bindings/clock/adi,max32-gcr.yaml @@ -0,0 +1,36 @@ +# Copyright (c) 2023-2024 Analog Devices, Inc. +# SPDX-License-Identifier: Apache-2.0 + +description: MAX32 Global Control + +compatible: "adi,max32-gcr" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 2 + + sysclk-prescaler: + type: int + enum: + - 1 + - 2 + - 4 + - 8 + - 16 + - 32 + - 64 + - 128 + + description: | + SYSCLK prescaler. Defines actual core clock frequency SYSCLK + based on system frequency input. Some MAX32xxx devices does not + support this feature, check your device user guide before using it. + +clock-cells: + - offset + - bit diff --git a/include/zephyr/drivers/clock_control/adi_max32_clock_control.h b/include/zephyr/drivers/clock_control/adi_max32_clock_control.h new file mode 100644 index 00000000000..2922b5e2c88 --- /dev/null +++ b/include/zephyr/drivers/clock_control/adi_max32_clock_control.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023-2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_ADI_MAX32_CLOCK_CONTROL_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_ADI_MAX32_CLOCK_CONTROL_H_ + +#include + +#include + +#include + +/** Driver structure definition */ + +struct max32_perclk { + uint32_t bus; + uint32_t bit; + + /* Peripheral clock source: + * Can be (see: adi_max32_clock.h file): + * + * ADI_MAX32_PRPH_CLK_SRC_PCLK + * ADI_MAX32_PRPH_CLK_SRC_EXTCLK + * ADI_MAX32_PRPH_CLK_SRC_IBRO + * ADI_MAX32_PRPH_CLK_SRC_ERFO + * ADI_MAX32_PRPH_CLK_SRC_ERTCO + * ADI_MAX32_PRPH_CLK_SRC_INRO + * ADI_MAX32_PRPH_CLK_SRC_ISO + * ADI_MAX32_PRPH_CLK_SRC_IBRO_DIV8 + */ + uint32_t clk_src; +}; + +/** Get prescaler value if it defined */ +#define ADI_MAX32_SYSCLK_PRESCALER DT_PROP_OR(DT_NODELABEL(gcr), sysclk_prescaler, 1) + +#define ADI_MAX32_CLK_IPO_FREQ DT_PROP(DT_NODELABEL(clk_ipo), clock_frequency) +#define ADI_MAX32_CLK_ERFO_FREQ DT_PROP(DT_NODELABEL(clk_erfo), clock_frequency) +#define ADI_MAX32_CLK_IBRO_FREQ DT_PROP(DT_NODELABEL(clk_ibro), clock_frequency) +#define ADI_MAX32_CLK_ISO_FREQ DT_PROP_OR(DT_NODELABEL(clk_iso), clock_frequency, 0) +#define ADI_MAX32_CLK_INRO_FREQ DT_PROP(DT_NODELABEL(clk_inro), clock_frequency) +#define ADI_MAX32_CLK_ERTCO_FREQ DT_PROP(DT_NODELABEL(clk_ertco), clock_frequency) +/* External clock may not be defined so _OR is used */ +#define ADI_MAX32_CLK_EXTCLK_FREQ DT_PROP_OR(DT_NODELABEL(clk_extclk), clock_frequency, 0) + +#define DT_GCR_CLOCKS_CTRL DT_CLOCKS_CTLR(DT_NODELABEL(gcr)) + +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_ipo)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_IPO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_IPO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_erfo)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_ERFO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_ERFO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_ibro)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_IBRO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_IBRO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_iso)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_ISO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_ISO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_inro)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_INRO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_INRO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_ertco)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_ERTCO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_ERTCO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif +#if DT_SAME_NODE(DT_GCR_CLOCKS_CTRL, DT_NODELABEL(clk_extclk)) +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_EXTCLK +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_EXTCLK_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif + +#ifndef ADI_MAX32_SYSCLK_SRC +#define ADI_MAX32_SYSCLK_SRC ADI_MAX32_CLK_IPO +#define ADI_MAX32_SYSCLK_FREQ (ADI_MAX32_CLK_IPO_FREQ / ADI_MAX32_SYSCLK_PRESCALER) +#endif + +#define ADI_MAX32_PCLK_FREQ (ADI_MAX32_SYSCLK_FREQ / 2) + +#define ADI_MAX32_GET_PRPH_CLK_FREQ(clk_src) \ + ((clk_src) == ADI_MAX32_PRPH_CLK_SRC_PCLK ? ADI_MAX32_PCLK_FREQ \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_IBRO ? ADI_MAX32_CLK_IBRO_FREQ \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_ERFO ? ADI_MAX32_CLK_ERFO_FREQ \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_ERTCO ? ADI_MAX32_CLK_ERTCO_FREQ \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_INRO ? ADI_MAX32_CLK_INRO_FREQ \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_ISO ? ADI_MAX32_CLK_ISO_FREQ \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_IBRO_DIV8 ? (ADI_MAX32_CLK_IBRO_FREQ / 8) \ + : (clk_src) == ADI_MAX32_PRPH_CLK_SRC_EXTCLK ? ADI_MAX32_CLK_EXTCLK_FREQ \ + : 0) + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_ADI_MAX32_CLOCK_CONTROL_H_ */ diff --git a/include/zephyr/dt-bindings/clock/adi_max32_clock.h b/include/zephyr/dt-bindings/clock/adi_max32_clock.h new file mode 100644 index 00000000000..44fb918c22e --- /dev/null +++ b/include/zephyr/dt-bindings/clock/adi_max32_clock.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2023-2024 Analog Devices, Inc. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_ADI_MAX32_CLOCK_H_ +#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_ADI_MAX32_CLOCK_H_ + +/** Peripheral clock register */ +#define ADI_MAX32_CLOCK_BUS0 0 +#define ADI_MAX32_CLOCK_BUS1 1 +#define ADI_MAX32_CLOCK_BUS2 2 + +/** Clock source for peripheral interfaces like UART, WDT... */ +#define ADI_MAX32_PRPH_CLK_SRC_PCLK 0 /* Peripheral clock */ +#define ADI_MAX32_PRPH_CLK_SRC_EXTCLK 1 /* External clock */ +#define ADI_MAX32_PRPH_CLK_SRC_IBRO 2 /* Internal Baud Rate Oscillator*/ +#define ADI_MAX32_PRPH_CLK_SRC_ERFO 3 /* External RF Oscillator */ +#define ADI_MAX32_PRPH_CLK_SRC_ERTCO 4 /* External RTC Oscillator */ +#define ADI_MAX32_PRPH_CLK_SRC_INRO 5 /* Internal Nano Ring Oscillator */ +#define ADI_MAX32_PRPH_CLK_SRC_ISO 6 /* Internal Secondary Oscillator */ +#define ADI_MAX32_PRPH_CLK_SRC_IBRO_DIV8 7 /* IBRO/8 */ + +#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_ADI_MAX32_CLOCK_H_ */