AnsweredAssumed Answered

How to set clocks to play 44.1K/16BIT/2CH without changing fsl_ssi.c

Question asked by 计龙 杨 on Jul 5, 2019
Latest reply on Jul 5, 2019 by igorpadykov

I'm using imx-4.14.98-2.0.1_patch and TI TAS2505 codec. Here is my settings:

test.wav info:

U-Boot, according Table 61-7 in IMX6DQRM Rev5

void setup_audio(void)
{
    uint32_t reg, val;
    struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR;
    struct mxc_ccm_reg *ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;

    /* Set PLL4 to 632.2176 MHz:
        632.2176 MHz = 24 MHz * (27 - 157824/240000)
    */
    reg = readl(&anatop->pll_audio);
    reg = (reg & ~BM_ANADIG_PLL_AUDIO_DIV_SELECT) | BF_ANADIG_PLL_AUDIO_DIV_SELECT(27);
    writel(reg, &anatop->pll_audio);

    reg = readl(&anatop->pll_audio_num);
    reg = (reg & ~BM_ANADIG_PLL_AUDIO_NUM_A) | BF_ANADIG_PLL_AUDIO_NUM_A((0x20 << 24) + 0x1ffd9780); // -157824
    writel(reg, &anatop->pll_audio_num);

    reg = readl(&anatop->pll_audio_denom);
    reg = (reg & ~BM_ANADIG_PLL_AUDIO_DENOM_B) | BF_ANADIG_PLL_AUDIO_DENOM_B(240000);
    writel(reg, &anatop->pll_audio_denom);

    /* Set SSI2_DIV to (7 * 2) since pll4_post_div=4 defaultly */
    reg = readl(&ccm->cs2cdr);
    val = (((7 - 1) << MXC_CCM_CS2CDR_SSI2_CLK_PRED_OFFSET) & MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK) | \
         (((2 - 1) << MXC_CCM_CS2CDR_SSI2_CLK_PODF_OFFSET) & MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK);
    reg = (reg & ~(MXC_CCM_CS2CDR_SSI2_CLK_PRED_MASK | MXC_CCM_CS2CDR_SSI2_CLK_PODF_MASK)) | val;
    writel(reg, &ccm->cs2cdr);
}

 

Device Tree:

&clks {
    assigned-clocks = <&clks IMX6QDL_CLK_LDB_DI0_SEL>,
                     <&clks IMX6QDL_CLK_LDB_DI1_SEL>;
    assigned-clock-parents = <&clks IMX6QDL_CLK_PLL2_PFD0_352M>,
                             <&clks IMX6QDL_CLK_PLL2_PFD0_352M>;
};

&ssi2 {
    assigned-clocks = <&clks IMX6QDL_CLK_PLL4>,
                     <&clks IMX6QDL_PLL4_BYPASS>,
                     <&clks IMX6QDL_CLK_SSI2_SEL>,
                     <&clks IMX6QDL_CLK_CKO2_SEL>;
    assigned-clock-parents = <&clks IMX6QDL_CLK_OSC>,
                             <&clks IMX6QDL_CLK_PLL4>,
                             <&clks IMX6QDL_CLK_PLL4_POST_DIV>,
                             <&clks IMX6QDL_CLK_SSI2>;
    // assigned-clock-rates = <632217600>, <0>, <11289600>, <0>;

    clocks = <&clks IMX6QDL_CLK_CKO>, <&clks IMX6QDL_CLK_SSI2>;

    fsl,mode = "i2s-master";
    status = "okay";
};
    sound-tas2505 {
        compatible = "simple-audio-card";
        simple-audio-card,name = "tas2505";
        simple-audio-card,format = "i2s";
        simple-audio-card,bitclock-master = <&dailink0_master>;
        simple-audio-card,frame-master = <&dailink0_master>;
        // simple-audio-card,mclk-fs = <512>;
        
        dailink0_master: simple-audio-card,cpu {
            sound-dai = <&ssi2>;
            system-clock-frequency = <1411200>;
        };
        
        simple-audio-card,codec {
            sound-dai = <&tas2505>;
        };
    };
    tas2505: tas2505@18 {
        #sound-dai-cells = <0>;
        compatible = "fsl,tas2505";
        reg = <0x18>;
        enable-gpio = <&gpio5 6 GPIO_ACTIVE_HIGH>;
        muteon_poweroff = "false";
    };

fsl_ssi.c in kernal

static int fsl_ssi_set_bclk()
{
    // ...
    dev_err(cpu_dai->dev,
        "%s(baudclk_is_used=%d)\n\t\t"
        "i(%u), factor(%u), div2(%u), psr(%u), pm(%u), stccr(%u)\n\t\t"
        "ipgclk(%lu), ssi_baudclk(%lu), ssi_bitclk(%u)\n\t\t"
        "freq(%u), afreq(%u), clkrate(%lu), baudrate(%lu), tmprate(%lu)\n\t\t"
        "sub(%llu), savesub(%llu)\n",
        __func__, baudclk_is_used,
        i, factor, div2, psr, pm, stccr,
        clk_get_rate(ssi_private->clk), clk_get_rate(ssi_private->baudclk), ssi_private->bitclk_freq,
        freq, afreq, clkrate, baudrate, tmprate,
        sub, savesub);

    if (!baudclk_is_used) {
        ret = clk_set_rate(ssi_private->baudclk, baudrate*2);
        if (ret) {
            dev_err(cpu_dai->dev, "failed to set baudclk rate\n");
            return -EINVAL;
        }
    }
}

 

log output:

Playing WAVE './snd/test.wav' : Signed 16 bit Little Endian, Rate 44100 Hz, Stereo
[ 32.668653] fsl-ssi-dai 202c000.ssi: fsl_ssi_set_bclk(baudclk_is_used=0)
[ 32.668653] i(1), factor(2), div2(0), psr(0), pm(1), stccr(1)
[ 32.668653] ipgclk(11289600), ssi_baudclk(11289600), ssi_bitclk(1411200)
[ 32.668653] freq(1411200), afreq(1411200), clkrate(2822400), baudrate(5644800), tmprate(5644800)
[ 32.668653] sub(0), savesub(0)

I have to double baudrate variable to make it works, otherwise "failed to set baudclk rate" reported.

But really don't want to change and hardcode fsl_ssi.c

Outcomes