diff --git a/drivers/clock_control/CMakeLists.txt b/drivers/clock_control/CMakeLists.txt index 5e73ba3da20b175..bf3b89adba8a469 100644 --- a/drivers/clock_control/CMakeLists.txt +++ b/drivers/clock_control/CMakeLists.txt @@ -11,6 +11,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_LPC11U6X clock_cont zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCHP_XEC clock_control_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM clock_control_mcux_ccm.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM_REV2 clock_control_mcux_ccm_rev2.c) +zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_CCM_REV3 clock_control_mcux_ccm_rev3.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_MCG clock_control_mcux_mcg.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_PCC clock_control_mcux_pcc.c) zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_MCUX_SCG clock_control_mcux_scg.c) diff --git a/drivers/clock_control/Kconfig b/drivers/clock_control/Kconfig index c74808e692ebba7..9f75ebe7234990e 100644 --- a/drivers/clock_control/Kconfig +++ b/drivers/clock_control/Kconfig @@ -74,4 +74,6 @@ source "drivers/clock_control/Kconfig.smartbond" source "drivers/clock_control/Kconfig.numaker" +source "drivers/clock_control/Kconfig.mcux_ccm_rev3" + endif # CLOCK_CONTROL diff --git a/drivers/clock_control/Kconfig.mcux_ccm_rev3 b/drivers/clock_control/Kconfig.mcux_ccm_rev3 new file mode 100644 index 000000000000000..6bccf4706da79d8 --- /dev/null +++ b/drivers/clock_control/Kconfig.mcux_ccm_rev3 @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: Apache-2.0 + +config CLOCK_CONTROL_MCUX_CCM_REV3 + bool "MCUX CCM Rev3 driver" + default y + depends on DT_HAS_NXP_IMX_CCM_REV3_ENABLED + help + Enable support for mcux ccm rev3 driver. diff --git a/drivers/clock_control/clock_control_mcux_ccm_rev3.c b/drivers/clock_control/clock_control_mcux_ccm_rev3.c new file mode 100644 index 000000000000000..7db9f157e82d9af --- /dev/null +++ b/drivers/clock_control/clock_control_mcux_ccm_rev3.c @@ -0,0 +1,102 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include + +/* Used for driver binding */ +#define DT_DRV_COMPAT nxp_imx_ccm_rev3 + +extern struct imx_ccm_data imx_ccm_data; +extern struct imx_ccm_config imx_ccm_config; + +static int mcux_ccm_on_off(const struct device *dev, + clock_control_subsys_t sys, bool on) +{ + uint32_t clock_name; + const struct imx_ccm_config *cfg; + + clock_name = (uintptr_t)sys; + cfg = dev->config; + + /* validate clock_name */ + if (clock_name >= cfg->clock_config->clock_num) + return -EINVAL; + + return imx_ccm_clock_on_off(dev, &cfg->clock_config->clocks[clock_name], on); +} + +static int mcux_ccm_on(const struct device *dev, clock_control_subsys_t sys) +{ + return mcux_ccm_on_off(dev, sys, true); +} + +static int mcux_ccm_off(const struct device *dev, clock_control_subsys_t sys) +{ + return mcux_ccm_on_off(dev, sys, false); +} + +static int mcux_ccm_get_rate(const struct device *dev, + clock_control_subsys_t sys, uint32_t *rate) +{ + uint32_t clock_name, returned_rate; + const struct imx_ccm_config *cfg; + + clock_name = (uintptr_t)sys; + cfg = dev->config; + + /* validate clock_name */ + if (clock_name >= cfg->clock_config->clock_num) + return -EINVAL; + + returned_rate = imx_ccm_clock_get_rate(dev, &cfg->clock_config->clocks[clock_name]); + + if (returned_rate > 0) { + *rate = returned_rate; + return 0; + } else { + return returned_rate; + } +} + +static int mcux_ccm_set_rate(const struct device *dev, + clock_control_subsys_t sys, clock_control_subsys_rate_t rate) +{ + uint32_t clock_name, requested_rate; + const struct imx_ccm_config *cfg; + + clock_name = (uintptr_t)sys; + requested_rate = (uintptr_t)rate; + cfg = dev->config; + + /* validate clock_name */ + if (clock_name >= cfg->clock_config->clock_num) + return -EINVAL; + + return imx_ccm_clock_set_rate(dev, &cfg->clock_config->clocks[clock_name], requested_rate); +} + +static int mcux_ccm_init(const struct device *dev) +{ + return imx_ccm_init(dev); +} + +static const struct clock_control_driver_api mcux_ccm_driver_api = { + .on = mcux_ccm_on, + .off = mcux_ccm_off, + .get_rate = mcux_ccm_get_rate, + .set_rate = mcux_ccm_set_rate, +}; + +/* there's only one CCM per SoC */ +DEVICE_DT_INST_DEFINE(0, + &mcux_ccm_init, + NULL, + &imx_ccm_data, &imx_ccm_config, + PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY, + &mcux_ccm_driver_api); diff --git a/dts/bindings/clock/nxp,imx-ccm-rev3.yaml b/dts/bindings/clock/nxp,imx-ccm-rev3.yaml new file mode 100644 index 000000000000000..61781632981ef38 --- /dev/null +++ b/dts/bindings/clock/nxp,imx-ccm-rev3.yaml @@ -0,0 +1,19 @@ +# Copyright 2023 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: i.MX CCM (Clock Controller Module) Rev 3 IP node + +compatible: "nxp,imx-ccm-rev3" + +include: [clock-controller.yaml, base.yaml] + +properties: + reg: + required: true + + "#clock-cells": + const: 2 + +clock-cells: + - name + - freq diff --git a/include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h b/include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h new file mode 100644 index 000000000000000..7ea4e153326c536 --- /dev/null +++ b/include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h @@ -0,0 +1,149 @@ +/* + * Copyright 2023 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCUX_CCM_H_ +#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCUX_CCM_H_ + +#include +#include + +#define IMX_CCM_MAX_SOURCES 4 + +#define IMX_CCM_FIXED_FREQ(src) ((src).source.fixed.freq) +#define IMX_CCM_PLL_MAX_FREQ(src) ((src).source.pll.max_freq) +#define IMX_CCM_RATE_LIMIT(src) \ + ((src).type == IMX_CCM_TYPE_FIXED ? \ + IMX_CCM_FIXED_FREQ(src) : IMX_CCM_PLL_MAX_FREQ(src)) + +enum imx_ccm_clock_state { + IMX_CCM_CLOCK_STATE_INIT = 0, /* initial state - clock may be gated or not */ + IMX_CCM_CLOCK_STATE_GATED, /* clock is gated */ + IMX_CCM_CLOCK_STATE_UNGATED, /* clock is not gated */ +}; + +enum imx_ccm_type { + IMX_CCM_TYPE_FIXED = 1, + IMX_CCM_TYPE_PLL, + IMX_CCM_TYPE_MAX, +}; + +struct imx_ccm_fixed { + char *name; + uint32_t id; + uint32_t freq; +}; + +struct imx_ccm_pll { + char *name; + uint32_t id; + uint32_t max_freq; /* maximum allowed frequency */ + uint32_t offset; /* offset from PLL regmap */ +}; + +struct imx_ccm_source { + enum imx_ccm_type type; /* source type - fixed or PLL */ + union { + struct imx_ccm_fixed fixed; + struct imx_ccm_pll pll; + } source; +}; + +struct imx_ccm_clock_root { + char *name; + uint32_t id; + struct imx_ccm_source sources[IMX_CCM_MAX_SOURCES]; + uint32_t source_num; +}; + +struct imx_ccm_clock { + char *name; + uint32_t id; + struct imx_ccm_clock_root root; + + uint32_t lpcg_regmap_phys; + uint32_t lpcg_regmap_size; + mm_reg_t lpcg_regmap; + + uint32_t state; +}; + +/* there are a few possible restrictions regarding the clock array: + * + * 1) The index of the clock sources needs to match the + * MUX value. + * e.g: + * The clock root called lpuartx_clock_root has + * the following possible MUX values: + * 00 => PLL0 + * 01 => PLL1 + * 10 => PLL2 + * 11 => PLL3 + * This means that the clock root structure needs + * to be defined as follows: + * struct imx_ccm_clock_root root = { + * .name = "some_name", + * .id = ID_FROM_NXP_HAL, + * .sources = {PLL0, PLL1, PLL2, PLL3}, + * .source_num = 4, + * } + * * note: this restriction is optional as some developers may choose not to + * follow it for their SoC. + * + * + * 2) The macros defined in zephyr/clock/soc_name_ccm.h need to match the indexes + * from the clock array. + * e.g: lpuart1_clock is found at index 5 in the clock array. This means + * that SOC_NAME_LPUART1_CLOCK needs to have value 5. + * + * * note: this restriction is mandatory as it's used in the CCM driver. + * + * 3) The ID value from a clock IP/root/source needs to be a value from the NXP HAL. + * * note: this restriction is optional as some developers may choose not + * to follow it for their SoC. + */ +struct imx_ccm_clock_config { + uint32_t clock_num; + struct imx_ccm_clock *clocks; +}; + +struct imx_ccm_config { + struct imx_ccm_clock_config *clock_config; + + uint32_t regmap_phys; + uint32_t regmap_size; + + uint32_t pll_regmap_phys; + uint32_t pll_regmap_size; +}; + + +struct imx_ccm_data { + mm_reg_t regmap; + mm_reg_t pll_regmap; + + uint32_t ipc_handle; +}; + +/* disable/enable a given clock + * + * it's up to the user of the clock control API to + * make sure that the sequence of operations is valid. + */ +int imx_ccm_clock_on_off(const struct device *dev, struct imx_ccm_clock *clk, bool on); + +/* get the frequency of a given clock */ +int imx_ccm_clock_get_rate(const struct device *dev, struct imx_ccm_clock *clk); + +/* set the rate of a clock. + * + * if successful, the function will return the new rate which + * may differ from the requested rate. + */ +int imx_ccm_clock_set_rate(const struct device *dev, struct imx_ccm_clock *clk, uint32_t rate); + +int imx_ccm_init(const struct device *dev); + +#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MCUX_CCM_H_ */