博主使用的是天嵌科技的IMX6Q_coreC板子。
使用的内核版本为3.0.35
现在有关项目需要clko2输出40M时钟。
记录调试过程:
板级代码中有:
管脚复用以配置成 MX6Q_PAD_GPIO_3__CCM_CLKO2
clko2 = clk_get(NULL, "clko2_clk");
if (IS_ERR(clko2))
pr_err("can't get CLKO2 clock.\n");
new_parent = clk_get(NULL, "osc_clk");
if (!IS_ERR(new_parent))
{
clk_set_parent(clko2, new_parent);
clk_put(new_parent);
}
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
/* Camera and audio use osc clock */
clko = clk_get(NULL, "clko_clk");
if (!IS_ERR(clko))
clk_set_parent(clko, clko2);
就是clko是从clko2中分出来的,而clko2是从osc_clk中分出来的,osc_clk是24M,用示波器量clko(GPIO0)是有24M的, clko2应该也是有24M才对啊,但是量得clko2却没有时钟输出
后来我在板级代码上改成这样
clko2 = clk_get(NULL, "clko2_clk");
if (IS_ERR(clko2))
pr_err("can't get CLKO2 clock.\n");
new_parent = clk_get(NULL, "osc_clk");
if (!IS_ERR(new_parent))
{
clk_set_parent(clko2, new_parent);
clk_put(new_parent);
}
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
在声卡的代码 static int mxc_wm8960_init(void)中改成这样:
clko2 = clk_get(NULL, "clko2_clk");
if (IS_ERR(clko2))
pr_err("can't get CLKO2 clock.\n");
new_parent = clk_get(NULL, "osc_clk");
if (!IS_ERR(new_parent))
{
clk_set_parent(clko2, new_parent);
clk_put(new_parent);
}
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
不将clko2设置成clko的父时钟,用示波器测量clko2_clk(GPIO_3),同样没有24M输出。
后来又改成这样:
static int mxc_wm8960_init(void)中改成这样:
clko2 = clk_get(NULL, "clko2_clk");
if (IS_ERR(clko2))
pr_err("can't get CLKO2 clock.\n");
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
而 static int wm8960_clk_enable(int enable)
{
if (enable)
clk_enable(clko2);
else
clk_disable(clko2);
return 0;
}
直接设置clko2,不将osc_clk设置成clko2的父时钟,用示波器测量clko2_clk(GPIO_3),同样没有24M输出。
后来我跟了一下代码:
我跟了一下代码:static int _clk_clko_set_parent(struct clk *clk, struct clk *parent)
{
u32 sel, reg;
if (parent == &pll3_usb_otg_main_clk)
sel = 0;
else if (parent == &pll2_528_bus_main_clk)
sel = 1;
else if (parent == &pll1_sys_main_clk)
sel = 2;
else if (parent == &pll5_video_main_clk)
sel = 3;
else if (parent == &axi_clk)
sel = 5;
else if (parent == &enfc_clk)
sel = 6;
else if (parent == &ipu1_di_clk[0])
sel = 7;
else if (parent == &ipu1_di_clk[1])
sel = 8;
else if (parent == &ipu2_di_clk[0])
sel = 9;
else if (parent == &ipu2_di_clk[1])
sel = 10;
else if (parent == &ahb_clk)
sel = 11;
else if (parent == &ipg_clk)
sel = 12;
else if (parent == &ipg_perclk)
sel = 13;
else if (parent == &ckil_clk)
sel = 14;
else if (parent == &pll4_audio_main_clk)
sel = 15;
else if (parent == &clko2_clk) {
reg = __raw_readl(MXC_CCM_CCOSR);
reg |= MXC_CCM_CCOSR_CKOL_MIRROR_CKO2_MASK;
__raw_writel(reg, MXC_CCM_CCOSR);
return 0;
} else
return -EINVAL;
reg = __raw_readl(MXC_CCM_CCOSR);
reg &= ~(MXC_CCM_CCOSR_CKOL_MIRROR_CKO2_MASK |
MXC_CCM_CCOSR_CKOL_SEL_MASK);
reg |= sel << MXC_CCM_CCOSR_CKOL_SEL_OFFSET;
__raw_writel(reg, MXC_CCM_CCOSR);
return 0;
}
从这个函数中可以看出clko要获取 24M 只有选clko2上(parent),其他的选择基本都达不到24M
clko2 的话 :static int _clk_clko2_set_parent(struct clk *clk, struct clk *parent)
{
u32 sel, reg;
if (parent == &mmdc_ch0_axi_clk[0])
sel = 0;
else if (parent == &mmdc_ch1_axi_clk[0])
sel = 1;
else if (parent == &usdhc4_clk)
sel = 2;
else if (parent == &usdhc1_clk)
sel = 3;
else if (parent == &gpu2d_axi_clk)
sel = 4;
else if (parent == &ecspi_clk[0])
sel = 6;
else if (parent == &gpu3d_axi_clk)
sel = 7;
else if (parent == &usdhc3_clk)
sel = 8;
else if (parent == &pcie_clk[0])
sel = 9;
else if (parent == &ipu1_clk)
sel = 11;
else if (parent == &ipu2_clk)
sel = 12;
else if (parent == &vdo_axi_clk)
sel = 13;
else if (parent == &osc_clk)
sel = 14;
else if (parent == &gpu2d_core_clk[0])
sel = 15;
else if (parent == &gpu3d_core_clk[0])
sel = 16;
else if (parent == &usdhc2_clk)
sel = 17;
else if (parent == &ssi1_clk)
sel = 18;
else if (parent == &ssi2_clk)
sel = 19;
else if (parent == &ssi3_clk)
sel = 20;
else if (parent == &gpu3d_shader_clk)
sel = 21;
else if (parent == &can_clk_root)
sel = 23;
else if (parent == &ldb_di0_clk)
sel = 24;
else if (parent == &ldb_di1_clk)
sel = 25;
else if (parent == &esai_clk)
sel = 26;
else if (parent == &uart_clk[0])
sel = 28;
else if (parent == &spdif0_clk[0])
sel = 29;
else if (parent == &hsi_tx_clk[0])
sel = 31;
else
return -EINVAL;
reg = __raw_readl(MXC_CCM_CCOSR);
reg &= ~MXC_CCM_CCOSR_CKO2_SEL_MASK;
reg |= sel << MXC_CCM_CCOSR_CKO2_SEL_OFFSET;
__raw_writel(reg, MXC_CCM_CCOSR);
return 0;
}他的选择比较多, 在系统初始化的的时候,系统确实是选择了osc_clk
在mx6_clocks_init函数中会有以下的初始化佐证:
/* PCLK camera - J5 */
clk_set_parent(&clko2_clk, &osc_clk);
clk_set_rate(&clko2_clk, 2400000);
clk_set_parent(&clko_clk, &pll4_audio_main_clk);
但在板级代码中又重新了初始化的,就是前面提到的代码:
clko2 = clk_get(NULL, "clko2_clk");
if (IS_ERR(clko2))
pr_err("can't get CLKO2 clock.\n");
new_parent = clk_get(NULL, "osc_clk");
if (!IS_ERR(new_parent))
{
clk_set_parent(clko2, new_parent);
clk_put(new_parent);
}
rate = clk_round_rate(clko2, 24000000);
clk_set_rate(clko2, rate);
clk_enable(clko2);
/* Camera and audio use osc clock */
clko = clk_get(NULL, "clko_clk");
if (!IS_ERR(clko))
clk_set_parent(clko, clko2);
clko2还是选择了osc_clk 作为父时钟 , clko就选择了clko2作为父时钟。
另外还发现clko除了使用clko2(osc_clk )作为父时钟,使用其他时钟作为父时钟,clko也没有输出。
后来怀疑clko2端口到CPU没有通路,然后将该接口复用成GPIO进行检测,发现可控制高低电平,说明硬件上没有问题。
后面怀疑该管脚的复用寄存器有问题。
故分别读取寄存器的值:
IOMUXC_SW_MUX_CTL_PAD_GPIO03 寄存器值为0x4 将该管脚复用成CCM_CLKO2
IOMUXC_SW_PAD_CTL_PAD_GPIO03 寄存器值为1b8b1
极有可能是这个寄存器配置不正确了: IOMUXC_SW_PAD_CTL_PAD_GPIO03
查看datasheet:
可能是第11bit的或者第16bit导致,尝试改变这两位的测量波形。
发现将第11bit置0后有波形输出,即将 IOMUXC_SW_PAD_CTL_PAD_GPIO03值设置为1B0B1。
记录完毕