Browse Source

drivers: Add MAX32690 clock control driver

Clock control for MAX32690

Co-authored-by: Okan Sahin <okan.sahin@analog.com>
Signed-off-by: Sadik Ozer <sadik.ozer@analog.com>
pull/72136/head
Sadik Ozer 2 years ago committed by Henrik Brix Andersen
parent
commit
45df8963f1
  1. 1
      drivers/clock_control/CMakeLists.txt
  2. 2
      drivers/clock_control/Kconfig
  3. 9
      drivers/clock_control/Kconfig.max32
  4. 158
      drivers/clock_control/clock_control_max32.c
  5. 36
      dts/bindings/clock/adi,max32-gcr.yaml
  6. 98
      include/zephyr/drivers/clock_control/adi_max32_clock_control.h
  7. 25
      include/zephyr/dt-bindings/clock/adi_max32_clock.h

1
drivers/clock_control/CMakeLists.txt

@ -76,3 +76,4 @@ if(CONFIG_CLOCK_CONTROL_RCAR_CPG_MSSR) @@ -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)

2
drivers/clock_control/Kconfig

@ -82,6 +82,8 @@ source "drivers/clock_control/Kconfig.agilex5" @@ -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"

9
drivers/clock_control/Kconfig.max32

@ -0,0 +1,9 @@ @@ -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.

158
drivers/clock_control/clock_control_max32.c

@ -0,0 +1,158 @@ @@ -0,0 +1,158 @@
/*
* Copyright (c) 2023-2024 Analog Devices, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
#include <wrap_max32_sys.h>
#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);

36
dts/bindings/clock/adi,max32-gcr.yaml

@ -0,0 +1,36 @@ @@ -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

98
include/zephyr/drivers/clock_control/adi_max32_clock_control.h

@ -0,0 +1,98 @@ @@ -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 <zephyr/drivers/clock_control.h>
#include <zephyr/dt-bindings/clock/adi_max32_clock.h>
#include <wrap_max32_sys.h>
/** 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_ */

25
include/zephyr/dt-bindings/clock/adi_max32_clock.h

@ -0,0 +1,25 @@ @@ -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_ */
Loading…
Cancel
Save