drivers: clock_control: microchip: add drivers for sama7g5 PMC

Initialize the configurations for PMC driver.
Add implement of the API for PMC clocks.

Signed-off-by: Tony Han <tony.han@microchip.com>
This commit is contained in:
Tony Han
2025-04-27 10:00:18 +08:00
committed by Benjamin Cabé
parent 21da37b400
commit 8f5a0559c6
6 changed files with 264 additions and 0 deletions

View File

@@ -27,6 +27,7 @@ zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_NRF_DRIVER_CALIBRATION nrf_clo
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_RV32M1_PCC clock_control_rv32m1_pcc.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_INFINEON_CAT1 clock_control_ifx_cat1.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAM clock_control_sam_pmc.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SAMA7G5 clock_control_sama7g5_pmc.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SILABS_SIWX91X clock_control_silabs_siwx91x.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SILABS_SERIES clock_control_silabs_series.c)
zephyr_library_sources_ifdef(CONFIG_CLOCK_CONTROL_SI32_PLL clock_control_si32_pll.c)

View File

@@ -7,3 +7,10 @@ config CLOCK_CONTROL_SAM
depends on DT_HAS_ATMEL_SAM_PMC_ENABLED
help
Enable driver for Atmel SAM Clock Control.
config CLOCK_CONTROL_SAMA7G5
bool "Microchip SAMA7G5 Power Management Controller (PMC)"
default y
depends on DT_HAS_MICROCHIP_SAM_PMC_ENABLED
help
Enable driver for Microchip SAMA7G5 Power Management Controller (PMC).

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT microchip_sam_pmc
#include <pmc.h>
#include <zephyr/device.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/drivers/clock_control/mchp_sam_pmc.h>
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(pmc, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
static int get_pmc_clk(const struct device *dev, clock_control_subsys_t sys,
struct device **clk)
{
const struct sam_clk_cfg *cfg = (const struct sam_clk_cfg *)sys;
const struct sam_pmc_data *data = dev->data;
if (cfg == NULL || data == NULL) {
LOG_ERR("The PMC config and data can not be NULL.");
return -ENXIO;
}
LOG_DBG("Type: %x, Id: %d", cfg->clock_type, cfg->clock_id);
*clk = sam_pmc_get_clock(cfg, data->pmc);
if (*clk) {
return 0;
}
LOG_ERR("The PMC clock type is not implemented.");
return -ENODEV;
}
static int sam_clock_control_on(const struct device *dev,
clock_control_subsys_t sys)
{
struct device *clk;
int ret = get_pmc_clk(dev, sys, &clk);
if (!ret) {
return clock_control_on(clk, sys);
}
return ret;
}
static int sam_clock_control_off(const struct device *dev,
clock_control_subsys_t sys)
{
struct device *clk;
int ret = get_pmc_clk(dev, sys, &clk);
if (!ret) {
return clock_control_off(clk, sys);
}
return ret;
}
static int sam_clock_control_get_rate(const struct device *dev,
clock_control_subsys_t sys,
uint32_t *rate)
{
struct device *clk;
int ret = get_pmc_clk(dev, sys, &clk);
if (!ret) {
return clock_control_get_rate(clk, sys, rate);
}
return ret;
}
static enum clock_control_status
sam_clock_control_get_status(const struct device *dev,
clock_control_subsys_t sys)
{
struct device *clk;
int ret = get_pmc_clk(dev, sys, &clk);
if (!ret) {
return clock_control_get_status(clk, sys);
}
return ret;
}
static int clock_control_sam_pmc_init(const struct device *dev)
{
sam_pmc_setup(dev);
return 0;
}
static DEVICE_API(clock_control, sam_clock_control_api) = {
.on = sam_clock_control_on,
.off = sam_clock_control_off,
.get_rate = sam_clock_control_get_rate,
.get_status = sam_clock_control_get_status,
};
#define PMC_INIT_CFG_SLCK(n, slck) \
COND_CODE_1(DT_INST_CLOCKS_HAS_NAME(n, slck), \
( \
.slck = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_NAME(n, slck)), \
.slck##_cfg = { \
.crystal_osc = DT_INST_CLOCKS_CELL_BY_NAME(n, slck, \
clock_crystal_osc), \
}, \
), ())
#define PMC_INIT_CFG_CLK(n, clk) \
COND_CODE_1(DT_INST_CLOCKS_HAS_NAME(n, clk), \
( \
.clk = DEVICE_DT_GET(DT_CLOCKS_CTLR_BY_NAME(DT_DRV_INST(n), clk)), \
), ())
#define PMC_CFG_DEFN(n) \
static const struct sam_pmc_cfg pmc##n##_cfg = { \
.reg = (uint32_t *)DT_INST_REG_ADDR(n), \
PMC_INIT_CFG_SLCK(n, td_slck) \
PMC_INIT_CFG_SLCK(n, md_slck) \
PMC_INIT_CFG_CLK(n, main_xtal) \
}
#define SAM_PMC_DEVICE_INIT(n) \
static struct sam_pmc_data pmc##n##data; \
PMC_CFG_DEFN(n); \
\
DEVICE_DT_INST_DEFINE(n, clock_control_sam_pmc_init, NULL, \
&pmc##n##data, \
&pmc##n##_cfg, \
PRE_KERNEL_1, \
CONFIG_CLOCK_CONTROL_INIT_PRIORITY, \
&sam_clock_control_api); \
DT_INST_FOREACH_STATUS_OKAY(SAM_PMC_DEVICE_INIT)

View File

@@ -0,0 +1,22 @@
# Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
#
# SPDX-License-Identifier: Apache-2.0
#
description: |
Microchip Power Management Controller (PMC)
compatible: "microchip,sam-pmc"
include: [clock-controller.yaml, base.yaml]
properties:
reg:
required: true
"#clock-cells":
const: 2
clock-cells:
- clock-type
- peripheral-id

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MICROCHIP_SAM_PMC_H_
#define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MICROCHIP_SAM_PMC_H_
#include <soc.h>
#include <zephyr/drivers/clock_control.h>
#include <zephyr/dt-bindings/clock/microchip_sam_pmc.h>
struct sam_sckc_config {
uint32_t crystal_osc: 1;
uint32_t reserved: 31;
};
struct sam_clk_cfg {
uint32_t clock_type;
uint32_t clock_id;
};
/* Device constant configuration parameters */
struct sam_pmc_cfg {
uint32_t *const reg;
const struct device *td_slck;
const struct device *md_slck;
const struct device *main_xtal;
const struct sam_sckc_config td_slck_cfg;
const struct sam_sckc_config md_slck_cfg;
};
/* Device run time data */
struct sam_pmc_data {
struct pmc_data *pmc;
};
#define SAM_DT_CLOCK_PMC_CFG(clock, node_id) { \
.clock_type = DT_CLOCKS_CELL_BY_IDX(node_id, \
clock, \
clock_type), \
.clock_id = DT_CLOCKS_CELL_BY_IDX(node_id, \
clock, \
peripheral_id) \
}
#define SAM_DT_INST_CLOCK_PMC_CFG(inst) SAM_DT_CLOCK_PMC_CFG(0, DT_DRV_INST(inst))
#define SAM_DT_CLOCKS_PMC_CFG(node_id) { \
LISTIFY(DT_NUM_CLOCKS(node_id), \
SAM_DT_CLOCK_PMC_CFG, (,), node_id) \
}
#define SAM_DT_INST_CLOCKS_PMC_CFG(inst) SAM_DT_CLOCKS_PMC_CFG(DT_DRV_INST(inst))
#endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_MICROCHIP_SAM_PMC_H_ */

View File

@@ -0,0 +1,36 @@
/*
* Copyright (C) 2025 Microchip Technology Inc. and its subsidiaries
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MICROCHIP_SAM_PMC_H_
#define ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MICROCHIP_SAM_PMC_H_
#define PMC_TYPE_CORE 0
#define PMC_TYPE_SYSTEM 1
#define PMC_TYPE_PERIPHERAL 2
#define PMC_TYPE_GCK 3
#define PMC_TYPE_PROGRAMMABLE 4
#define PMC_SLOW 0
#define PMC_MCK 1
#define PMC_UTMI 2
#define PMC_MAIN 3
/* SAMA7G5 */
#define PMC_CPUPLL (PMC_MAIN + 1)
#define PMC_SYSPLL (PMC_MAIN + 2)
#define PMC_DDRPLL (PMC_MAIN + 3)
#define PMC_IMGPLL (PMC_MAIN + 4)
#define PMC_BAUDPLL (PMC_MAIN + 5)
#define PMC_AUDIOPMCPLL (PMC_MAIN + 6)
#define PMC_AUDIOIOPLL (PMC_MAIN + 7)
#define PMC_ETHPLL (PMC_MAIN + 8)
#define PMC_CPU (PMC_MAIN + 9)
#define PMC_MCK1 (PMC_MAIN + 10)
#define UTMI1 0
#define UTMI2 1
#define UTMI3 2
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_MICROCHIP_SAM_PMC_H_ */