1268 lines
36 KiB
C
1268 lines
36 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* AR100 SYSTEM
|
|
* AR100 Software System Develop Kits
|
|
* clock control unit module
|
|
*
|
|
* (c) Copyright 2012-2016, Sunny China
|
|
* All Rights Reserved
|
|
*
|
|
* File : mclk.c
|
|
* By : Superm
|
|
* Version : v1.0
|
|
* Date : 2016-7-13
|
|
* Descript: module clock management
|
|
* Update : date auther ver notes
|
|
* 2016-7-13 8:43:10 Superm 1.0 Create this file.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
#include "ccu_i.h"
|
|
#include "hal_prcm.h"
|
|
#include "errno.h"
|
|
#include "aw_io.h"
|
|
#include "aw_common.h"
|
|
#include "errno.h"
|
|
#include "compiler_attributes.h"
|
|
#include "notifier.h"
|
|
#include "delay.h"
|
|
|
|
static u32 ccu_log2(u32 m)
|
|
{
|
|
u32 n = 0;
|
|
|
|
while (m >= 2) {
|
|
m = m >> 1;
|
|
n++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
void ccu_iosc_freq_update(void)
|
|
{
|
|
if (ccu_get_mclk_src(CCU_MOD_CLK_APBS2) == CCU_SYS_CLK_IOSC) {
|
|
notifier_notify(&apbs2_notifier_head, CCU_CLK_CLKCHG_REQ, iosc_freq / ccu_get_mclk_div(CCU_MOD_CLK_APBS2));
|
|
notifier_notify(&apbs2_notifier_head, CCU_CLK_CLKCHG_DONE, iosc_freq / ccu_get_mclk_div(CCU_MOD_CLK_APBS2));
|
|
}
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* SET SOURCE OF MODULE CLOCK
|
|
*
|
|
* Description: set the source of a specific module clock.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to set source.
|
|
* sclk : the source clock ID whick we want to set as source.
|
|
*
|
|
* Returns : OK if set source succeeded, others if failed.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_set_mclk_src(u32 mclk, u32 sclk)
|
|
{
|
|
switch (mclk) {
|
|
case CCU_MOD_CLK_CPUS: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC: {
|
|
ccu_reg_addr->cpus_clk_cfg.src_sel = 0;
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_LOSC: {
|
|
ccu_reg_addr->cpus_clk_cfg.src_sel = 1;
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_IOSC: {
|
|
ccu_reg_addr->cpus_clk_cfg.src_sel = 2;
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_AUDIO1_2X: {
|
|
ccu_reg_addr->cpus_clk_cfg.src_sel = 3;
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_AUDIO0_DIV2: {
|
|
ccu_reg_addr->cpus_clk_cfg.src_sel = 4;
|
|
return OK;
|
|
}
|
|
default: {
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_APBS2: {
|
|
u32 src_freq;
|
|
u32 src_sel;
|
|
u32 factor_m;
|
|
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC: {
|
|
src_freq = CCU_HOSC_FREQ;
|
|
src_sel = 0;
|
|
factor_m = 0;
|
|
break;
|
|
}
|
|
case CCU_SYS_CLK_LOSC: {
|
|
src_freq = losc_freq;
|
|
src_sel = 1;
|
|
factor_m = 0;
|
|
break;
|
|
}
|
|
case CCU_SYS_CLK_IOSC: {
|
|
src_freq = iosc_freq;
|
|
src_sel = 2;
|
|
factor_m = 0;
|
|
break;
|
|
}
|
|
/* apbs max freq is 200MHz */
|
|
case CCU_SYS_CLK_PERI_2X: {
|
|
src_freq = CCU_PERIPH0_FREQ / 3;
|
|
src_sel = 3;
|
|
factor_m = 2;
|
|
break;
|
|
}
|
|
case CCU_SYS_CLK_AUDIO0_DIV2: {
|
|
src_freq = CCU_PERIPH0_FREQ / 3;
|
|
src_sel = 4;
|
|
factor_m = 2;
|
|
return -ENOTSUP;
|
|
}
|
|
default: {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
notifier_notify(&apbs2_notifier_head, CCU_CLK_CLKCHG_REQ,
|
|
src_freq / ccu_get_mclk_div(CCU_MOD_CLK_APBS2));
|
|
ccu_reg_addr->apbs2_cfg.factor_m = factor_m;
|
|
udelay(2);
|
|
ccu_reg_addr->apbs2_cfg.src_sel = src_sel;
|
|
notifier_notify(&apbs2_notifier_head, CCU_CLK_CLKCHG_DONE,
|
|
src_freq / ccu_get_mclk_div(CCU_MOD_CLK_APBS2));
|
|
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_C0: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x0 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_LOSC: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x1 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_IOSC: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x2 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_CPUX: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x3 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PERI_1X: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x4 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PERI_2X: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x5 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PERI_800M: {
|
|
writel(((readl(CCU_CPU_AXI_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x6 << 24)),
|
|
CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
default: {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_PSI:
|
|
case CCU_MOD_CLK_AHB1:
|
|
case CCU_MOD_CLK_AHB2: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC: {
|
|
writel(((readl(CCU_PSI_AHB1_AHB2_CFG_REG) &
|
|
(~(0x3 << 24))) |
|
|
(0x0 << 24)),
|
|
CCU_PSI_AHB1_AHB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_LOSC: {
|
|
writel(((readl(CCU_PSI_AHB1_AHB2_CFG_REG) &
|
|
(~(0x3 << 24))) |
|
|
(0x1 << 24)),
|
|
CCU_PSI_AHB1_AHB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_IOSC: {
|
|
writel(((readl(CCU_PSI_AHB1_AHB2_CFG_REG) &
|
|
(~(0x3 << 24))) |
|
|
(0x2 << 24)),
|
|
CCU_PSI_AHB1_AHB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PERI_1X: {
|
|
writel(((readl(CCU_PSI_AHB1_AHB2_CFG_REG) &
|
|
(~(0x3 << 24))) |
|
|
(0x3 << 24)),
|
|
CCU_PSI_AHB1_AHB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
default: {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_APB1: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC: {
|
|
writel(((readl(CCU_APB1_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x0 << 24)),
|
|
CCU_APB1_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_LOSC: {
|
|
writel(((readl(CCU_APB1_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x1 << 24)),
|
|
CCU_APB1_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PSI: {
|
|
writel(((readl(CCU_APB1_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x2 << 24)),
|
|
CCU_APB1_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PERI_1X: {
|
|
writel(((readl(CCU_APB1_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x3 << 24)),
|
|
CCU_APB1_CFG_REG);
|
|
return OK;
|
|
}
|
|
default: {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_APB2: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC: {
|
|
writel(((readl(CCU_APB2_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x0 << 24)),
|
|
CCU_APB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_LOSC: {
|
|
writel(((readl(CCU_APB2_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x1 << 24)),
|
|
CCU_APB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PSI: {
|
|
writel(((readl(CCU_APB2_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x2 << 24)),
|
|
CCU_APB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_PERI_1X: {
|
|
writel(((readl(CCU_APB2_CFG_REG) & (~(0x3 << 24))) |
|
|
(0x3 << 24)),
|
|
CCU_APB2_CFG_REG);
|
|
return OK;
|
|
}
|
|
default: {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_CIR_SP: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_LOSC: {
|
|
ccu_reg_addr->r_ir_clk.src_sel = 0;
|
|
return OK;
|
|
}
|
|
case CCU_SYS_CLK_HOSC: {
|
|
ccu_reg_addr->r_ir_clk.src_sel = 1;
|
|
return OK;
|
|
}
|
|
default: {
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_AC_ADC: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_ac_adc.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_ac_adc.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_ac_adc.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_ac_adc.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_AC_DAC: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_ac_dac.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_ac_dac.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_ac_dac.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_ac_dac.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_DMIC: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_dmic.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_dmic.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_dmic.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_dmic.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_i2s0.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_i2s0.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_i2s0.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_i2s0.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0_ASRC: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_i2s0_asrc.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_i2s0_asrc.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_i2s0_asrc.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_i2s0_asrc.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_I2S1: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_i2s1.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_i2s1.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_i2s1.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_i2s1.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_R_LPSD: {
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_AUDIO0_DIV5:
|
|
ccu_reg_addr->r_lpsd.src_sel = 0;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO0_DIV2:
|
|
ccu_reg_addr->r_lpsd.src_sel = 1;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_1X:
|
|
ccu_reg_addr->r_lpsd.src_sel = 2;
|
|
return OK;
|
|
case CCU_SYS_CLK_AUDIO1_4X:
|
|
ccu_reg_addr->r_lpsd.src_sel = 3;
|
|
return OK;
|
|
default:
|
|
/* invalid source id for module clock */
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
default: {
|
|
pr_warning("invaid module clock id (%d) when set source\n", mclk);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
/* un-reached */
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* GET SOURCE OF MODULE CLOCK
|
|
*
|
|
* Description: get the source of a specific module clock.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to get source.
|
|
*
|
|
* Returns : the source clock ID of source clock.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_get_mclk_src(u32 mclk)
|
|
{
|
|
switch (mclk) {
|
|
case CCU_MOD_CLK_CPUS:
|
|
{
|
|
switch (ccu_reg_addr->cpus_clk_cfg.src_sel) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_IOSC;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_PERI_2X;
|
|
}
|
|
case 4:
|
|
{
|
|
return CCU_SYS_CLK_AUDIO0_DIV2;
|
|
}
|
|
default:
|
|
{
|
|
/* invalid source id for module clock */
|
|
return CCU_SYS_CLK_NONE;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_C0:
|
|
{
|
|
switch ((readl(CCU_CPU_AXI_CFG_REG) >> 24) & 0x3) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_IOSC;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_CPUX;
|
|
}
|
|
case 4:
|
|
{
|
|
return CCU_SYS_CLK_PERI_1X;
|
|
}
|
|
case 5:
|
|
{
|
|
return CCU_SYS_CLK_PERI_2X;
|
|
}
|
|
case 6:
|
|
{
|
|
return CCU_SYS_CLK_PERI_800M;
|
|
}
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_PSI:
|
|
case CCU_MOD_CLK_AHB1:
|
|
case CCU_MOD_CLK_AHB2:
|
|
{
|
|
switch ((readl(CCU_PSI_AHB1_AHB2_CFG_REG) >> 24) & 0x3) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_IOSC;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_PERI_1X;
|
|
}
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_APB1:
|
|
{
|
|
switch ((readl(CCU_APB1_CFG_REG) >> 24) & 0x3) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_PSI;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_PERI_1X;
|
|
}
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_APB2:
|
|
{
|
|
switch ((readl(CCU_APB2_CFG_REG) >> 24) & 0x3) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_PSI;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_PERI_1X;
|
|
}
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
case CCU_MOD_CLK_AHBS:
|
|
{
|
|
return CCU_SYS_CLK_CPUS;
|
|
}
|
|
case CCU_MOD_CLK_APBS1:
|
|
{
|
|
switch (ccu_reg_addr->apbs1_cfg.src_sel) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_IOSC;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_PERI_2X;
|
|
}
|
|
case 4:
|
|
{
|
|
return CCU_SYS_CLK_AUDIO0_DIV2;
|
|
}
|
|
default:
|
|
{
|
|
return CCU_SYS_CLK_NONE;
|
|
}
|
|
}
|
|
return CCU_MOD_CLK_AHBS;
|
|
}
|
|
case CCU_MOD_CLK_APBS2:
|
|
{
|
|
switch (ccu_reg_addr->apbs2_cfg.src_sel) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 2:
|
|
{
|
|
return CCU_SYS_CLK_IOSC;
|
|
}
|
|
case 3:
|
|
{
|
|
return CCU_SYS_CLK_PERI_2X;
|
|
}
|
|
case 4:
|
|
{
|
|
return CCU_SYS_CLK_AUDIO0_DIV2;
|
|
}
|
|
default:
|
|
{
|
|
return CCU_SYS_CLK_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
case CCU_MOD_CLK_R_ONEWIRE:
|
|
case CCU_MOD_CLK_R_TIMER0_1:
|
|
case CCU_MOD_CLK_R_CIR:
|
|
case CCU_MOD_CLK_R_PIO:
|
|
{
|
|
return CCU_SYS_CLK_APB1;
|
|
}
|
|
case CCU_MOD_CLK_R_RSB:
|
|
case CCU_MOD_CLK_R_TWI:
|
|
case CCU_MOD_CLK_R_UART:
|
|
{
|
|
return CCU_SYS_CLK_APB2;
|
|
}
|
|
case CCU_MOD_CLK_R_CIR_SP:
|
|
{
|
|
switch (ccu_reg_addr->r_ir_clk.src_sel) {
|
|
case 0:
|
|
{
|
|
return CCU_SYS_CLK_LOSC;
|
|
}
|
|
case 1:
|
|
{
|
|
return CCU_SYS_CLK_HOSC;
|
|
}
|
|
default:
|
|
{
|
|
return CCU_SYS_CLK_NONE;
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
{
|
|
pr_warning("invaid module clock id (%d) when set source\n",
|
|
mclk);
|
|
return CCU_SYS_CLK_NONE;
|
|
}
|
|
}
|
|
/* un-reached */
|
|
}
|
|
|
|
s32 calc_clk_audio_ratio_nm(u32 div, u32 *n, u32 *m)
|
|
{
|
|
if (div < 33) {
|
|
*n = 0;
|
|
} else if (div < 65) {
|
|
*n = 1;
|
|
} else if (div < 129) {
|
|
*n = 2;
|
|
} else if (div < 257) {
|
|
*n = 3;
|
|
} else {
|
|
*n = 0;
|
|
*m = 0;
|
|
printf("audio_ratio: %x\n", div);
|
|
return -EINVAL;
|
|
}
|
|
*m = div / (1 << (*n)) - 1;
|
|
return OK;
|
|
}
|
|
|
|
s32 calc_clk_ratio_nm(u32 div, u32 *n, u32 *m)
|
|
{
|
|
if (div < 17) {
|
|
*n = 0;
|
|
*m = div;
|
|
} else if (div < 33) {
|
|
*n = 1;
|
|
*m = (div + 1) / 2;
|
|
} else if (div < 65) {
|
|
*n = 2;
|
|
*m = (div + 3) / 4;
|
|
} else if (div < 129) {
|
|
*n = 3;
|
|
*m = (div + 7) / 8;
|
|
} else {
|
|
pr_err("icd %x\n", div);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* SET DIVIDER OF MODULE CLOCK
|
|
*
|
|
* Description: set the divider of a specific module clock.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to set divider.
|
|
* div : the divider whick we want to set as source.
|
|
*
|
|
* Returns : OK if set divider succeeded, others if failed.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_set_mclk_div(u32 mclk, u32 div)
|
|
{
|
|
switch (mclk) {
|
|
case CCU_MOD_CLK_CPUS:
|
|
{
|
|
ccu_reg_addr->cpus_clk_cfg.factor_n =
|
|
ccu_log2(div);
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_APBS1:
|
|
{
|
|
ccu_reg_addr->apbs1_cfg.factor_m = div - 1;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_APBS2:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->apbs2_cfg.factor_n = ccu_log2(factor_n);
|
|
ccu_reg_addr->apbs2_cfg.factor_m = factor_m - 1;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_CIR_SP:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_ir_clk.factor_n = ccu_log2(factor_n);
|
|
ccu_reg_addr->r_ir_clk.factor_m = factor_m - 1;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_AXI:
|
|
{
|
|
volatile u32 value;
|
|
value = readl(CCU_CPU_AXI_CFG_REG);
|
|
value &= (~(0x3));
|
|
value |= ((div - 1) & 0x3);
|
|
writel(value, CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_CPU_APB:
|
|
{
|
|
volatile u32 value;
|
|
value = readl(CCU_CPU_AXI_CFG_REG);
|
|
value &= (~(0x3 << 8));
|
|
value |= ((div - 1) & 0x3) << 8;
|
|
writel(value, CCU_CPU_AXI_CFG_REG);
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_PSI:
|
|
case CCU_MOD_CLK_AHB1:
|
|
case CCU_MOD_CLK_AHB2:
|
|
{
|
|
volatile u32 value;
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
value = readl(CCU_PSI_AHB1_AHB2_CFG_REG);
|
|
value &= (~(0x3ff << 0));
|
|
value |= (ccu_log2(factor_n) << 8) | (factor_m - 1);
|
|
writel(value, CCU_PSI_AHB1_AHB2_CFG_REG);
|
|
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_APB1:
|
|
{
|
|
volatile u32 value;
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
value = readl(CCU_APB1_CFG_REG);
|
|
value &= (~(0x3ff << 0));
|
|
value |= (ccu_log2(factor_n) << 8) | (factor_m - 1);
|
|
writel(value, CCU_APB1_CFG_REG);
|
|
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_APB2:
|
|
{
|
|
volatile u32 value;
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
value = readl(CCU_APB2_CFG_REG);
|
|
value &= (~(0x3ff << 0));
|
|
value |= (ccu_log2(factor_n) << 8) | (factor_m - 1);
|
|
writel(value, CCU_APB2_CFG_REG);
|
|
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_LPSD:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_lpsd.factor_n = factor_n;
|
|
ccu_reg_addr->r_lpsd.factor_m0 = factor_m;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_AC_ADC:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_ac_adc.factor_n = factor_n;
|
|
ccu_reg_addr->r_ac_adc.factor_m = factor_m;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_AC_DAC:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_ac_dac.factor_n = factor_n;
|
|
ccu_reg_addr->r_ac_dac.factor_m = factor_m;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_i2s0.factor_n = factor_n;
|
|
ccu_reg_addr->r_i2s0.factor_m = factor_m;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0_ASRC:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_i2s0_asrc.factor_n = factor_n;
|
|
ccu_reg_addr->r_i2s0_asrc.factor_m = factor_m;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S1:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_i2s1.factor_n = factor_n;
|
|
ccu_reg_addr->r_i2s1.factor_m = factor_m;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_DMIC:
|
|
{
|
|
u32 factor_n;
|
|
u32 factor_m;
|
|
|
|
if (calc_clk_audio_ratio_nm(div, &factor_n, &factor_m) != OK) {
|
|
return -EFAULT;
|
|
}
|
|
ccu_reg_addr->r_dmic.factor_n = factor_n;
|
|
ccu_reg_addr->r_dmic.factor_m = factor_m;
|
|
return OK;
|
|
}
|
|
default:
|
|
{
|
|
pr_warning("invaid module clock id (%d) when set divider\n",
|
|
mclk);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
/* un-reached */
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* GET DIVIDER OF MODULE CLOCK
|
|
*
|
|
* Description: get the divider of a specific module clock.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to get divider.
|
|
*
|
|
* Returns : the divider of the specific module clock.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_get_mclk_div(u32 mclk)
|
|
{
|
|
switch (mclk) {
|
|
case CCU_MOD_CLK_CPUS: {
|
|
return 1 << (ccu_reg_addr->cpus_clk_cfg.factor_n);
|
|
}
|
|
case CCU_MOD_CLK_AHBS: {
|
|
return 1;
|
|
}
|
|
case CCU_MOD_CLK_APBS1: {
|
|
return (ccu_reg_addr->apbs1_cfg.factor_m + 1);
|
|
}
|
|
case CCU_MOD_CLK_APBS2: {
|
|
return 1 << (ccu_reg_addr->apbs2_cfg.factor_n);
|
|
}
|
|
case CCU_MOD_CLK_R_RTC:
|
|
case CCU_MOD_CLK_R_CPUSCFG:
|
|
case CCU_MOD_CLK_R_PRCM:
|
|
case CCU_MOD_CLK_R_TIMER0_1:
|
|
case CCU_MOD_CLK_R_WDG:
|
|
case CCU_MOD_CLK_R_TWD:
|
|
case CCU_MOD_CLK_R_PWM:
|
|
case CCU_MOD_CLK_R_INTC:
|
|
case CCU_MOD_CLK_R_PIO:
|
|
case CCU_MOD_CLK_R_CIR:
|
|
case CCU_MOD_CLK_R_ONEWIRE:
|
|
case CCU_MOD_CLK_R_TWI:
|
|
case CCU_MOD_CLK_R_UART:
|
|
case CCU_MOD_CLK_R_RSB: {
|
|
return 1;
|
|
}
|
|
case CCU_MOD_CLK_R_AC_ADC: {
|
|
return (ccu_reg_addr->r_ac_adc.factor_m + 1) *
|
|
ccu_reg_addr->r_ac_adc.factor_n;
|
|
}
|
|
case CCU_MOD_CLK_R_AC_DAC: {
|
|
return (ccu_reg_addr->r_ac_dac.factor_m + 1) *
|
|
ccu_reg_addr->r_ac_dac.factor_n;
|
|
}
|
|
case CCU_MOD_CLK_R_DMIC: {
|
|
return (ccu_reg_addr->r_dmic.factor_m + 1) *
|
|
ccu_reg_addr->r_dmic.factor_n;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0: {
|
|
return (ccu_reg_addr->r_i2s0.factor_m + 1) *
|
|
ccu_reg_addr->r_i2s0.factor_n;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0_ASRC: {
|
|
return (ccu_reg_addr->r_i2s0_asrc.factor_m + 1) *
|
|
ccu_reg_addr->r_i2s0_asrc.factor_n;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S1: {
|
|
return (ccu_reg_addr->r_i2s1.factor_m + 1) *
|
|
ccu_reg_addr->r_i2s1.factor_n;
|
|
}
|
|
case CCU_MOD_CLK_R_CIR_SP: {
|
|
return (1 << (ccu_reg_addr->r_ir_clk.factor_n)) *
|
|
(ccu_reg_addr->r_ir_clk.factor_m + 1);
|
|
}
|
|
case CCU_MOD_CLK_AXI: {
|
|
volatile u32 value;
|
|
value = readl(CCU_CPU_AXI_CFG_REG);
|
|
return ((value & 0x3) + 1);
|
|
}
|
|
case CCU_MOD_CLK_CPU_APB: {
|
|
volatile u32 value;
|
|
value = readl(CCU_CPU_AXI_CFG_REG);
|
|
return (((value >> 8) & 0x3) + 1);
|
|
}
|
|
default: {
|
|
pr_warning("invaid module clock id (%d) when get divider\n",
|
|
mclk);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
/* un-reached */
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* SET ON-OFF STATUS OF MODULE CLOCK
|
|
*
|
|
* Description: set the on-off status of a specific module clock.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to set on-off status.
|
|
* onoff : the on-off status which we want to set, the detail please
|
|
* refer to the clock status of on-off.
|
|
*
|
|
* Returns : OK if set module clock on-off status succeeded, others if failed.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_set_mclk_onoff(u32 mclk, s32 onoff)
|
|
{
|
|
switch (mclk) {
|
|
case CCU_MOD_CLK_MSGBOX0:
|
|
writel(((readl(CCU_MSGBOX_BGR_REG) & (~(0x1 << 0))) |
|
|
(onoff << 0)),
|
|
CCU_MSGBOX_BGR_REG);
|
|
break;
|
|
case CCU_MOD_CLK_MSGBOX1:
|
|
writel(((readl(CCU_MSGBOX_BGR_REG) & (~(0x1 << 1))) |
|
|
(onoff << 1)),
|
|
CCU_MSGBOX_BGR_REG);
|
|
break;
|
|
case CCU_MOD_CLK_MSGBOXR:
|
|
writel(((readl(CCU_R_MSGBOX_BGR_REG) & (~(0x1 << 0))) |
|
|
(onoff << 0)),
|
|
CCU_R_MSGBOX_BGR_REG);
|
|
break;
|
|
case CCU_MOD_CLK_R_DMA:
|
|
/* bus gating */
|
|
writel(((readl(CCU_R_DMA_BGR_REG) & (~(0x1 << 0))) |
|
|
(onoff << 0)),
|
|
CCU_R_DMA_BGR_REG);
|
|
/* mclk gating */
|
|
writel(((readl(CCU_MBUS_MASTER_CLK_REG) & (~(0x1 << 3))) |
|
|
(onoff << 3)),
|
|
CCU_MBUS_MASTER_CLK_REG);
|
|
return OK;
|
|
case CCU_MOD_CLK_R_TWI: {
|
|
ccu_reg_addr->r_twi.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_UART: {
|
|
ccu_reg_addr->r_uart.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_TIMER0_1: {
|
|
ccu_reg_addr->r_timer.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_TWD: {
|
|
ccu_reg_addr->r_twd.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_PWM: {
|
|
ccu_reg_addr->r_pwm.gate = onoff;
|
|
return OK;
|
|
}
|
|
/* case CCU_MOD_CLK_R_ONEWIRE: { */
|
|
/* ccu_reg_addr->r_owc.gate = onoff; */
|
|
/* return OK; */
|
|
/* } */
|
|
case CCU_MOD_CLK_R_RTC: {
|
|
ccu_reg_addr->r_rtc.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_RSB: {
|
|
ccu_reg_addr->r_rsb.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_CIR: {
|
|
ccu_reg_addr->r_ir.gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_CIR_SP: {
|
|
ccu_reg_addr->r_ir_clk.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_SPINLOCK: {
|
|
writel(((readl(CCU_SPINLOCK_BGR_REG) & (~(0x1 << 0))) |
|
|
(onoff << 0)),
|
|
CCU_SPINLOCK_BGR_REG);
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_MSGBOX: {
|
|
writel(((readl(CCU_MSGBOX_BGR_REG) & (~(0x1 << 0))) |
|
|
(onoff << 0)),
|
|
CCU_MSGBOX_BGR_REG);
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_AC_ADC: {
|
|
ccu_reg_addr->r_ac_adc.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_AC_DAC: {
|
|
ccu_reg_addr->r_ac_dac.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_DMIC: {
|
|
ccu_reg_addr->r_dmic.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0: {
|
|
ccu_reg_addr->r_i2s0.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S0_ASRC: {
|
|
ccu_reg_addr->r_i2s0_asrc.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_I2S1: {
|
|
ccu_reg_addr->r_i2s1.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
case CCU_MOD_CLK_R_LPSD: {
|
|
ccu_reg_addr->r_lpsd.sclk_gate = onoff;
|
|
return OK;
|
|
}
|
|
default: {
|
|
pr_warning("invaid module clock id (%d) when set divider\n",
|
|
mclk);
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
/* un-reached */
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* REGISTER MODULE CB
|
|
*
|
|
* Description: register call-back for module clock, when the source frequency
|
|
* of the module clock changed, it will use this call-back to notify
|
|
* module driver.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to register call-back.
|
|
* pcb : the call-back which we want to register.
|
|
*
|
|
* Returns : OK if register call-back succeeded, others if failed.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_reg_mclk_cb(__maybe_unused u32 mclk, __pNotifier_t pcb)
|
|
{
|
|
/*
|
|
* we just support apb module clock notifier now.
|
|
* by sunny at 2012-11-23 14:36:14.
|
|
*/
|
|
|
|
/* insert call-back to apb_notifier_head. */
|
|
return notifier_insert(&apbs2_notifier_head, pcb);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* UNREGISTER MODULE CB
|
|
*
|
|
* Description: unregister call-back for module clock.
|
|
*
|
|
* Arguments : mclk : the module clock ID which we want to unregister call-back.
|
|
* pcb : the call-back which we want to unregister.
|
|
*
|
|
* Returns : OK if unregister call-back succeeded, others if failed.
|
|
*********************************************************************************************************
|
|
*/
|
|
s32 ccu_unreg_mclk_cb(__maybe_unused u32 mclk, __pNotifier_t pcb)
|
|
{
|
|
/* delete call-back to apb_notifier_head. */
|
|
return notifier_delete(&apbs2_notifier_head, pcb);
|
|
}
|
|
|
|
s32 ccu_set_cpus_src(u32 sclk)
|
|
{
|
|
u32 src_freq;
|
|
u32 src_sel;
|
|
|
|
switch (sclk) {
|
|
case CCU_SYS_CLK_HOSC:
|
|
{
|
|
src_freq = losc_freq;
|
|
src_sel = 0;
|
|
break;
|
|
}
|
|
case CCU_SYS_CLK_LOSC:
|
|
{
|
|
src_freq = CCU_HOSC_FREQ;
|
|
src_sel = 1;
|
|
break;
|
|
}
|
|
case CCU_SYS_CLK_IOSC:
|
|
{
|
|
src_freq = iosc_freq;
|
|
src_sel = 2;
|
|
break;
|
|
}
|
|
case CCU_SYS_CLK_PLL3:
|
|
{
|
|
src_freq = CCU_CPUS_POST_DIV;
|
|
src_sel = 3;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
/* set cpus clock source */
|
|
ccu_reg_addr->cpus_clk_cfg.src_sel = src_sel;
|
|
|
|
return OK;
|
|
}
|