Skip to content

Commit

Permalink
drivers: clock_control: Introduce revision 3 of CCM driver
Browse files Browse the repository at this point in the history
This commit introduces a new version of the CCM driver. The purpose of this
is to make the CCM driver usable by all NXP SoCs despite the changes in the
HAL API.

With this driver, each SoC will have to define its own clock tree and
a few common operations such as clock enable/disable, set_rate and
get_rate.

Signed-off-by: Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>
  • Loading branch information
LaurentiuM1234 committed Jun 27, 2023
1 parent a7498c3 commit 980f899
Show file tree
Hide file tree
Showing 6 changed files with 281 additions and 0 deletions.
1 change: 1 addition & 0 deletions drivers/clock_control/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions drivers/clock_control/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 8 additions & 0 deletions drivers/clock_control/Kconfig.mcux_ccm_rev3
Original file line number Diff line number Diff line change
@@ -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.
102 changes: 102 additions & 0 deletions drivers/clock_control/clock_control_mcux_ccm_rev3.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <errno.h>
#include <zephyr/sys/util.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h>

/* 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);
19 changes: 19 additions & 0 deletions dts/bindings/clock/nxp,imx-ccm-rev3.yaml
Original file line number Diff line number Diff line change
@@ -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
149 changes: 149 additions & 0 deletions include/zephyr/drivers/clock_control/clock_control_mcux_ccm_rev3.h
Original file line number Diff line number Diff line change
@@ -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 <stdint.h>
#include <zephyr/device.h>

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

0 comments on commit 980f899

Please sign in to comment.