zephyr/drivers/clock_control/clock_control_mcux_pcc.c
Laurentiu Mihalcea 139fcfa5f7 drivers: clock: clock_control_mcux_pcc: add support for 8ULP
This patch add supports for performing clock-related operations
on i.MX8ULP. This consists of:
	1) Adding a LUT.
	2) Adding an initialization function meant to tell the
	HAL which rate the XTALs on the boards (EVK and EVK9)
	run at. This is used by the functions that compute the
	rate of an IP clock.

Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
2024-04-02 14:30:27 +01:00

154 lines
3.4 KiB
C

/*
* Copyright (c) 2019 Vestas Wind Systems A/S
*
* Based on clock_control_rv32m1_pcc.c, which is:
* Copyright (c) 2018 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_kinetis_pcc
#include <errno.h>
#include <soc.h>
#include <zephyr/drivers/clock_control.h>
#include <fsl_clock.h>
#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(clock_control_mcux_pcc);
struct mcux_pcc_config {
uint32_t base_address;
uint32_t *clocks;
uint32_t clock_num;
};
#define DEV_BASE(dev) (((struct mcux_pcc_config *)(dev->config))->base_address)
#ifndef MAKE_PCC_REGADDR
#define MAKE_PCC_REGADDR(base, offset) ((base) + (offset))
#endif
static inline int get_clock_encoding(const struct device *dev,
clock_control_subsys_t sub_system,
uint32_t *clock_encoding)
{
const struct mcux_pcc_config *cfg;
uint32_t clock_name;
cfg = dev->config;
clock_name = POINTER_TO_UINT(sub_system);
if (!cfg->clock_num) {
*clock_encoding = MAKE_PCC_REGADDR(DEV_BASE(dev), clock_name);
return 0;
}
/* sanity check */
if (clock_name >= cfg->clock_num) {
return -EINVAL;
}
*clock_encoding = cfg->clocks[clock_name];
return 0;
}
static int mcux_pcc_on(const struct device *dev,
clock_control_subsys_t sub_system)
{
uint32_t clock_encoding;
int ret;
ret = get_clock_encoding(dev, sub_system, &clock_encoding);
if (ret < 0) {
return ret;
}
CLOCK_EnableClock(clock_encoding);
return 0;
}
static int mcux_pcc_off(const struct device *dev,
clock_control_subsys_t sub_system)
{
uint32_t clock_encoding;
int ret;
ret = get_clock_encoding(dev, sub_system, &clock_encoding);
if (ret < 0) {
return ret;
}
CLOCK_DisableClock(clock_encoding);
return 0;
}
static int mcux_pcc_get_rate(const struct device *dev,
clock_control_subsys_t sub_system,
uint32_t *rate)
{
uint32_t clock_encoding;
int ret;
ret = get_clock_encoding(dev, sub_system, &clock_encoding);
if (ret < 0) {
return ret;
}
*rate = CLOCK_GetIpFreq(clock_encoding);
return 0;
}
static const struct clock_control_driver_api mcux_pcc_api = {
.on = mcux_pcc_on,
.off = mcux_pcc_off,
.get_rate = mcux_pcc_get_rate,
};
static int mcux_pcc_init(const struct device *dev)
{
#ifdef CONFIG_SOC_MIMX8UD7
/* 8ULP's XTAL is set to 24MHz on EVK9. We keep
* this as SOC level because this should also be
* the case for the EVK board.
*/
CLOCK_SetXtal0Freq(24000000);
#endif /* CONFIG_SOC_MIMX8UD7 */
return 0;
}
#ifdef CONFIG_SOC_MIMX8UD7
static uint32_t clocks[] = {
/* clocks managed through PCC4 */
kCLOCK_Lpuart7,
};
#else
/* this is empty for SOCs which don't need a translation from
* the clock ID passed through the DTS and the clock ID encoding
* from the HAL. For these SOCs, the clock ID will be built based
* on the value passed from the DTS and the PCC base.
*/
static uint32_t clocks[] = {};
#endif /* CONFIG_SOC_MIMX8UD7 */
#define MCUX_PCC_INIT(inst) \
static const struct mcux_pcc_config mcux_pcc##inst##_config = { \
.base_address = DT_INST_REG_ADDR(inst), \
.clocks = clocks, \
.clock_num = ARRAY_SIZE(clocks), \
}; \
\
DEVICE_DT_INST_DEFINE(inst, \
&mcux_pcc_init, \
NULL, \
NULL, &mcux_pcc##inst##_config, \
PRE_KERNEL_1, \
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
&mcux_pcc_api);
DT_INST_FOREACH_STATUS_OKAY(MCUX_PCC_INIT)