Thread (11 messages) 11 messages, 3 authors, 2017-11-26

Re: [PATCH] ASoC: fsl_ssi: Override bit clock rate based on slot number

From: Arnaud Mouiche <hidden>
Date: 2017-09-13 08:02:31
Also in: alsa-devel, lkml


On 12/09/2017 23:32, Nicolin Chen wrote:
On Tue, Sep 12, 2017 at 04:35:13PM +0200, Arnaud Mouiche wrote:
quoted
quoted
- * freq: Output BCLK frequency = samplerate * 32 (fixed) * channels
- * dir: SND_SOC_CLOCK_OUT -> TxBCLK, SND_SOC_CLOCK_IN -> RxBCLK.
+ * freq: Output BCLK frequency = samplerate * 32 (fixed) * slots (or channels)
Slots are not necessarily 32 bits width.
Indeed, a simple grep of snd_soc_dai_set_tdm_slot shows 16, 24, 32
and 0 bits usage. (don't know the real meaning of 0 BTW...)
So, it should be good to also remember the slots width given in
snd_soc_dai_set_tdm_slot() call.
RM says that the word length is fixed to 32 in I2S Master mode.
So I used it here. But I think using it with the slots could be
wrong here as you stated. What kind of clock rates (bit and lr)
does a TDM case have?

The problem of slot width here is handled in the set_tdm_slot()
at all. So I tried to ignored that. But we probably do need it
when calculating things with the slot number.

Could you please give me a few set of examples of how you set
set_sysclk(), set_tdm_slot() with the current driver? The idea
here is to figure out a way to calculate the bclk in hw_params
without getting set_sysclk() involved any more.
Here is one, where a bclk = 4*16*fs is expected

    static int imx_hifi_hw_params(struct snd_pcm_substream *substream,
                          struct snd_pcm_hw_params *params)
    {
         struct snd_soc_pcm_runtime *rtd = substream->private_data;
         struct imx_priv *priv = &card_priv;
         struct device *dev = &priv->pdev->dev;

         int ret = 0;
         struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
         unsigned int freq;
         int ch;

         /* configuring cpu_dai
          * - bitclk  (fclk is computed automatically)
          *      16bit * 4 (max) channels * sampling rate
          * - tdm maskto select the active channels
          */

         freq = 4 * 16 * params_rate(params);
         if (freq != priv->current_freq) {
             /* clk_id and direction are not taken in count by fsl_ssi
    driver */
             ret = snd_soc_dai_set_sysclk( cpu_dai, 0, freq, 0 );
             if (ret) {
                 dev_err(dev, "failed to set cpu dai bitclk: %u\n", freq);
                 return ret;
             }
             priv->current_freq = freq;
         }
         ch = params_channels(params);
         if (ch != priv->current_ch) {
             ret = snd_soc_dai_set_tdm_slot( cpu_dai, (1 << ch)-1, (1 <<
    ch)-1, 4, 16 );
             if (ret) {
                 dev_err(dev, "failed to set cpu dai tdm slots:
    ch=%d\n", ch);
                 return ret;
             }
             priv->current_ch = ch;
         }
         return 0;
    }

In another setup, there are 8 x 16 bits slots, whatever the number of 
active channels is.
In this case bclk = 128 * fs
The number of slots is completely arbitrary. Some slots can even be 
reserved for communication between codecs that don't communicate with linux.
quoted
Anyway, there is something wrong in the snd_soc_codec_set_sysclk
usage by fsl_ssi
Let's get a look again at the description:

    /**
      * snd_soc_dai_set_sysclk - configure DAI system or master clock.
      * @dai: DAI
      * @clk_id: DAI specific clock ID
      * @freq: new clock frequency in Hz
      * @dir: new clock direction - input/output.
      *
      * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
      */
    int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
         unsigned int freq, int dir)

So, it can be used to configure 2 different clocks (and more) with
different usages.

Lukasz complains that simple-card is configuring MCLK incorrectly.
but simple-card, only want to configure the SYSCLK, whereas fsl_ssi
understand "configure the MCLK..." (fsl_ssi doesn't check the clk_id
at all)
It's more than a clock_id in my opinion. The driver now sets
the bit clock rate via set_sysclk() other than the MCLK rate
actually.
quoted
I think the problem is here.
I would propose a new clk_id

     #define FSL_SSI_SYSCLK_MCLK 1

And leave fsl_ssi_set_dai_sysclk(xxx, FSL_SSI_SYSCLK_MCLK, ...)
override the computed mlck.
This will leave a way for obscure TDM users to specify a specific a
random mclk frequency for obscure reasons...
Unfortunately, such generic clock_id (sysclk, mclk) were never
defined widely.
Unfortunately, it looks like a work around to me. I understand
the idea of leaving set_sysclk() out there to override the bit
clock is convenient, but it is not a standard ALSA design and
may eventually introduce new problems like today.
I agree. I'm not conservative at all concerning this question.
I don't see a way to remove set_sysclk without breaking current TDM 
users anyway, at least for those who don't have their code upstreamed.


All information provided through snd_soc_dai_set_tdm_slot( cpu_dai, 
mask, mask, slots, width ) should be enough
In this case, for TDM users

    bclk = slots * width * fs   (where slots is != channels)



will manage 99 % of the cases.
And the remaining 1% will concern people who need to hack the kernel so 
widely they don't care about the set_sysclk removal.

Now, looking at the code currently in linus/master:sound/soc/fsl 
concerning TDM
- imx-mc13783.c : the codec is master => OK
- fsl-asoc-card.c : *something will break since snd_soc_dai_set_sysclk 
returned code is checked*
- eukrea-tlv320.c : based on imx-ssi.c, so not affected by changes in 
fsl_ssi.c.  Use set_sysclk() only to setup the clock direction
- wm1133-ev1.c : bclk generated by the codec. set_sysclk() not called 
for cpu_dai

Consequently, we can say that few things is broken in linux upstream if 
set_sysclk is removed, and this can be fixed easily for fsl-asoc-card.c


Arnaud
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help