Browse Source
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
7 changed files with 329 additions and 0 deletions
@ -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. |
@ -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); |
@ -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 |
@ -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_ */ |
@ -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…
Reference in new issue