2016/4/1

imx6 CLKO

imx6 提供兩個 clock output: CLKO1, CLKO2

CLKO1 可以選擇 GPIO0 做 clk output
CLKO2 可以選擇 GPIO3 做 clk output

CLKO1.2 的控制 register 在 CCM_CCOSR (offset 0x60)

對照 kernel source : clk-imx6q.c
在 source code 李,叫 cko1, cko2
        clk[cko1]         = imx_clk_gate("cko1",           "cko1_podf",         base + 0x60, 7);
        clk[cko2]         = imx_clk_gate("cko2",           "cko2_podf",         base + 0x60, 24);
        ....
        clk[cko1_podf]        = imx_clk_divider("cko1_podf",        "cko1_sel",          base + 0x60, 4,  3);
        clk[cko2_podf]        = imx_clk_divider("cko2_podf",        "cko2_sel",          base + 0x60, 21, 3);
        ....
        clk[cko1_sel]         = imx_clk_mux("cko1_sel",         base + 0x60, 0,  4, cko1_sels,         ARRAY_SIZE(cko1_sels));
        clk[cko2_sel]         = imx_clk_mux("cko2_sel",         base + 0x60, 16, 5, cko2_sels,         ARRAY_SIZE(cko2_sels));
        ....

clk 是 struct clk

clk 軟體模型,依照一般 clk 的設置,叫下面的名子。:
  • clk source : parent, mux (imx_clk_mux)
  • divider : divider (imx_clk_divider)
  • enable/disable : gate (imx_clk_gate)
對照宣告的時候,後面的數字就是 register 的 offset, bit-shift , bit-width
拿 gate 來看,對照 datasheet, CCM_CCOSR:

  • bit 24: CLKO2_EN : enable/disable CLKO2
  • bit 21-23 : CLKO2_DIV : divider by 1,2,3,4...8
  • bit 16-20 : CLKO2_SEL : clko2 的 clk src
  • bit 7 : CLKO1_EN
  • bit 4-6 : CLKO1_DIV
  • bit 0-3 : CLKO1_SEL
可以對照看上面code 的宣告。

然後,因為這三個類型的操作不太相同,所以要為每個類型寫一個 operatio function.
各是:clk-gate2.c, clk-fixup-div.c, clk-fixup-mix.c

以 gate 來說。
implement imx_clk_gate 的code 在 clk-gate2.c
static struct clk_ops clk_gate2_ops = {
        .enable = clk_gate2_enable,
        .disable = clk_gate2_disable,
        .is_enabled = clk_gate2_is_enabled,
};
主要就是要實做這三個 gate 的 function.
enable/disable 最後 就是...
static void clk_gate2_do_hardware(struct clk_gate2 *gate, bool enable)
{
        u32 reg;

        reg = readl(gate->reg);
        if (enable)
                reg |= CCM_CCGR_FULL_ENABLE << gate->bit_idx;
        else
                reg &= ~(CCM_CCGR_FULL_ENABLE << gate->bit_idx);
        writel(reg, gate->reg);
}

統一的 clk interface 在 driver/clk/clk.c
呼叫 clk_enable( ) 就會:
static int __clk_enable(struct clk *clk)
{
        int ret = 0;

        if (!clk)
                return 0;

        if (WARN_ON(clk->prepare_count == 0))
                return -ESHUTDOWN;

        if (clk->enable_count == 0) {
                ret = __clk_enable(clk->parent);

                if (ret)
                        return ret;

                if (clk->ops->enable) {
                        ret = clk->ops->enable(clk->hw);
                        if (ret) {
                                __clk_disable(clk->parent);
                                return ret;
                        }
                }
        }

        clk->enable_count++;
        return 0;
}

-- 另外,一般用 clk_prepare_enable( )

所以,一定要 call 過 enable( ), 那個 clock 才會動。

沒有留言:

張貼留言