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 @@ |
|||||||
|
# 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 @@ |
|||||||
|
/*
|
||||||
|
* 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 @@ |
|||||||
|
# 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 @@ |
|||||||
|
/*
|
||||||
|
* 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 @@ |
|||||||
|
/*
|
||||||
|
* 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