Re: [alsa-devel][PATCH 1/3] ASoC: fsl_sai: add sai master mode support

2015-05-24 Thread Nicolin Chen
On Tue, May 12, 2015 at 03:07:39PM +0800, Zidan Wang wrote:
 When sai works on master mode, set its bit clock and frame clock.
 
 SAI has 4 MCLK source, bus clock, MCLK1, MCLK2 and MCLK3. fsl_sai_set_bclk
 will select proper MCLK source, then calculate and set the bit clock divider.
 
 After fsl_sai_set_bclk, enable the selected mclk in hw_params(), and add
 hw_free() to disable the mclk.

Besides these, there are also some bug-fixes that aren't related to
the topic while being a must to this support. I think at least you
should mention it in the commit log as well except you can separate
them into different small patches. (This includes copyright update)
 
 Signed-off-by: Zidan Wang zidan.w...@freescale.com
 ---
  sound/soc/fsl/fsl_sai.c | 117 
 ++--
  sound/soc/fsl/fsl_sai.h |   9 +++-
  2 files changed, 121 insertions(+), 5 deletions(-)
 
 diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
 index ee2671b..1ccc10d1 100644
 --- a/sound/soc/fsl/fsl_sai.c
 +++ b/sound/soc/fsl/fsl_sai.c
  
 +static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
 +{
 + struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
 + unsigned long clk_rate;
 + u32 savediv = 0, ratio, savesub = freq;
 + u32 id;
 + int ret = 0;
 +
 + /* Don't apply to slave mode */
 + if (sai-is_slave_mode)
 + return 0;
 +
 + for (id = 0; id  FSL_SAI_MCLK_MAX; id++) {
 + clk_rate = clk_get_rate(sai-mclk_clk[id]);
 + if (!clk_rate)
 + continue;
 +
 + ratio = clk_rate / freq;
 +
 + ret = clk_rate - ratio * freq;
 +
 + /*
 +  * Drop the source that can not be
 +  * divided into the required rate.
 +  */
 + if (ret != 0  clk_rate / ret  1000)
 + continue;
 +
 + dev_dbg(dai-dev,
 + ratio %d for freq %dHz based on clock %ldHz\n,
 + ratio, freq, clk_rate);
 +
 + if (ratio % 2 == 0  ratio = 2  ratio = 512)
 + ratio /= 2;
 + else
 + continue;
 +
 + if (ret  savesub) {
 + savediv = ratio;
 + sai-mclk_id[tx] = id;
 + savesub = ret;
 + }
 +
 + if (ret == 0)
 + break;
 + }
 +
 + if (savediv == 0) {
 + dev_err(dai-dev, failed to derive required %cx rate: %d\n,
 + tx ? 'T' : 'R', freq);
 + return -EINVAL;
 + }
 +
 + if ((tx  sai-synchronous[TX]) || (!tx  !sai-synchronous[RX])) {
 + regmap_update_bits(sai-regmap, FSL_SAI_RCR2,
 +FSL_SAI_CR2_MSEL_MASK,
 +FSL_SAI_CR2_MSEL(sai-mclk_id[tx]));
 + regmap_update_bits(sai-regmap, FSL_SAI_RCR2,
 +FSL_SAI_CR2_DIV_MASK, savediv - 1);
 + } else {
 + regmap_update_bits(sai-regmap, FSL_SAI_TCR2,
 +FSL_SAI_CR2_MSEL_MASK,
 +FSL_SAI_CR2_MSEL(sai-mclk_id[tx]));
 + regmap_update_bits(sai-regmap, FSL_SAI_TCR2,
 +FSL_SAI_CR2_DIV_MASK, savediv - 1);
 + }
 +
 + dev_dbg(dai-dev, best fit: clock id=%d, div=%d, deviation =%d\n,

id = %d, div = %d will be better

 + sai-mclk_id[tx], savediv, savesub);
 +
 + return 0;
 +}
 +
  static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
   struct snd_pcm_hw_params *params,
   struct snd_soc_dai *cpu_dai)
 @@ -297,6 +372,24 @@ static int fsl_sai_hw_params(struct snd_pcm_substream 
 *substream,
   unsigned int channels = params_channels(params);
   u32 word_width = snd_pcm_format_width(params_format(params));
   u32 val_cr4 = 0, val_cr5 = 0;
 + int ret;
 +
 + if (!sai-is_slave_mode) {
 + ret = fsl_sai_set_bclk(cpu_dai, tx,
 + 2 * word_width * params_rate(params));
 + if (ret)
 + return ret;
 +
 + /* Do not enable the clock if it is already enabled */
 + if (!(sai-mclk_streams  BIT(substream-stream))) {
 + ret = 
 clk_prepare_enable(sai-mclk_clk[sai-mclk_id[tx]]);
 + if (ret)
 + return ret;
 +
 + sai-mclk_streams |= BIT(substream-stream);
 + }
 +
 + }
  
   if (!sai-is_dsp_mode)
   val_cr4 |= FSL_SAI_CR4_SYWD(word_width);
 @@ -322,6 +415,22 @@ static int fsl_sai_hw_params(struct snd_pcm_substream 
 *substream,
   return 0;
  }
  
 +static int fsl_sai_hw_free(struct snd_pcm_substream *substream,
 + struct snd_soc_dai *cpu_dai)
 +{
 + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
 + bool 

[alsa-devel][PATCH 1/3] ASoC: fsl_sai: add sai master mode support

2015-05-12 Thread Zidan Wang
When sai works on master mode, set its bit clock and frame clock.

SAI has 4 MCLK source, bus clock, MCLK1, MCLK2 and MCLK3. fsl_sai_set_bclk
will select proper MCLK source, then calculate and set the bit clock divider.

After fsl_sai_set_bclk, enable the selected mclk in hw_params(), and add
hw_free() to disable the mclk.

Signed-off-by: Zidan Wang zidan.w...@freescale.com
---
 sound/soc/fsl/fsl_sai.c | 117 ++--
 sound/soc/fsl/fsl_sai.h |   9 +++-
 2 files changed, 121 insertions(+), 5 deletions(-)

diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index ee2671b..1ccc10d1 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -1,7 +1,7 @@
 /*
  * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
  *
- * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
  *
  * This program is free software, you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -251,12 +251,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai 
*cpu_dai,
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFM:
+   sai-is_slave_mode = true;
break;
case SND_SOC_DAIFMT_CBS_CFM:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+   sai-is_slave_mode = true;
break;
default:
return -EINVAL;
@@ -288,6 +290,79 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai 
*cpu_dai, unsigned int fmt)
return ret;
 }
 
+static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+{
+   struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+   unsigned long clk_rate;
+   u32 savediv = 0, ratio, savesub = freq;
+   u32 id;
+   int ret = 0;
+
+   /* Don't apply to slave mode */
+   if (sai-is_slave_mode)
+   return 0;
+
+   for (id = 0; id  FSL_SAI_MCLK_MAX; id++) {
+   clk_rate = clk_get_rate(sai-mclk_clk[id]);
+   if (!clk_rate)
+   continue;
+
+   ratio = clk_rate / freq;
+
+   ret = clk_rate - ratio * freq;
+
+   /*
+* Drop the source that can not be
+* divided into the required rate.
+*/
+   if (ret != 0  clk_rate / ret  1000)
+   continue;
+
+   dev_dbg(dai-dev,
+   ratio %d for freq %dHz based on clock %ldHz\n,
+   ratio, freq, clk_rate);
+
+   if (ratio % 2 == 0  ratio = 2  ratio = 512)
+   ratio /= 2;
+   else
+   continue;
+
+   if (ret  savesub) {
+   savediv = ratio;
+   sai-mclk_id[tx] = id;
+   savesub = ret;
+   }
+
+   if (ret == 0)
+   break;
+   }
+
+   if (savediv == 0) {
+   dev_err(dai-dev, failed to derive required %cx rate: %d\n,
+   tx ? 'T' : 'R', freq);
+   return -EINVAL;
+   }
+
+   if ((tx  sai-synchronous[TX]) || (!tx  !sai-synchronous[RX])) {
+   regmap_update_bits(sai-regmap, FSL_SAI_RCR2,
+  FSL_SAI_CR2_MSEL_MASK,
+  FSL_SAI_CR2_MSEL(sai-mclk_id[tx]));
+   regmap_update_bits(sai-regmap, FSL_SAI_RCR2,
+  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+   } else {
+   regmap_update_bits(sai-regmap, FSL_SAI_TCR2,
+  FSL_SAI_CR2_MSEL_MASK,
+  FSL_SAI_CR2_MSEL(sai-mclk_id[tx]));
+   regmap_update_bits(sai-regmap, FSL_SAI_TCR2,
+  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+   }
+
+   dev_dbg(dai-dev, best fit: clock id=%d, div=%d, deviation =%d\n,
+   sai-mclk_id[tx], savediv, savesub);
+
+   return 0;
+}
+
 static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
@@ -297,6 +372,24 @@ static int fsl_sai_hw_params(struct snd_pcm_substream 
*substream,
unsigned int channels = params_channels(params);
u32 word_width = snd_pcm_format_width(params_format(params));
u32 val_cr4 = 0, val_cr5 = 0;
+   int ret;
+
+   if (!sai-is_slave_mode) {
+   ret = fsl_sai_set_bclk(cpu_dai, tx,
+   2 * word_width * params_rate(params));
+   if (ret)
+   return ret;
+
+   /* Do not enable the clock if it is already enabled */
+   

Re: [PATCH 1/3] ASoC: fsl_sai: add sai master mode support

2015-05-12 Thread Mark Brown
On Mon, May 11, 2015 at 06:24:41PM +0800, Zidan Wang wrote:
 When sai works on master mode, set its bit clock and frame clock.
 
 SAI has 4 MCLK source, bus clock, MCLK1, MCLK2 and MCLK3. fsl_sai_set_bclk
 will select proper MCLK source, then calculate and set the bit clock divider.

Applied, thanks.


signature.asc
Description: Digital signature
___
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

[PATCH 1/3] ASoC: fsl_sai: add sai master mode support

2015-05-11 Thread Zidan Wang
When sai works on master mode, set its bit clock and frame clock.

SAI has 4 MCLK source, bus clock, MCLK1, MCLK2 and MCLK3. fsl_sai_set_bclk
will select proper MCLK source, then calculate and set the bit clock divider.

After fsl_sai_set_bclk, enable the selected mclk in hw_params(), and add
hw_free() to disable the mclk.

Signed-off-by: Zidan Wang zidan.w...@freescale.com
---
 sound/soc/fsl/fsl_sai.c | 117 ++--
 sound/soc/fsl/fsl_sai.h |   9 +++-
 2 files changed, 121 insertions(+), 5 deletions(-)

diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c
index ee2671b..1ccc10d1 100644
--- a/sound/soc/fsl/fsl_sai.c
+++ b/sound/soc/fsl/fsl_sai.c
@@ -1,7 +1,7 @@
 /*
  * Freescale ALSA SoC Digital Audio Interface (SAI) driver.
  *
- * Copyright 2012-2013 Freescale Semiconductor, Inc.
+ * Copyright 2012-2015 Freescale Semiconductor, Inc.
  *
  * This program is free software, you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -251,12 +251,14 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai 
*cpu_dai,
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFM:
+   sai-is_slave_mode = true;
break;
case SND_SOC_DAIFMT_CBS_CFM:
val_cr2 |= FSL_SAI_CR2_BCD_MSTR;
break;
case SND_SOC_DAIFMT_CBM_CFS:
val_cr4 |= FSL_SAI_CR4_FSD_MSTR;
+   sai-is_slave_mode = true;
break;
default:
return -EINVAL;
@@ -288,6 +290,79 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai 
*cpu_dai, unsigned int fmt)
return ret;
 }
 
+static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
+{
+   struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai);
+   unsigned long clk_rate;
+   u32 savediv = 0, ratio, savesub = freq;
+   u32 id;
+   int ret = 0;
+
+   /* Don't apply to slave mode */
+   if (sai-is_slave_mode)
+   return 0;
+
+   for (id = 0; id  FSL_SAI_MCLK_MAX; id++) {
+   clk_rate = clk_get_rate(sai-mclk_clk[id]);
+   if (!clk_rate)
+   continue;
+
+   ratio = clk_rate / freq;
+
+   ret = clk_rate - ratio * freq;
+
+   /*
+* Drop the source that can not be
+* divided into the required rate.
+*/
+   if (ret != 0  clk_rate / ret  1000)
+   continue;
+
+   dev_dbg(dai-dev,
+   ratio %d for freq %dHz based on clock %ldHz\n,
+   ratio, freq, clk_rate);
+
+   if (ratio % 2 == 0  ratio = 2  ratio = 512)
+   ratio /= 2;
+   else
+   continue;
+
+   if (ret  savesub) {
+   savediv = ratio;
+   sai-mclk_id[tx] = id;
+   savesub = ret;
+   }
+
+   if (ret == 0)
+   break;
+   }
+
+   if (savediv == 0) {
+   dev_err(dai-dev, failed to derive required %cx rate: %d\n,
+   tx ? 'T' : 'R', freq);
+   return -EINVAL;
+   }
+
+   if ((tx  sai-synchronous[TX]) || (!tx  !sai-synchronous[RX])) {
+   regmap_update_bits(sai-regmap, FSL_SAI_RCR2,
+  FSL_SAI_CR2_MSEL_MASK,
+  FSL_SAI_CR2_MSEL(sai-mclk_id[tx]));
+   regmap_update_bits(sai-regmap, FSL_SAI_RCR2,
+  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+   } else {
+   regmap_update_bits(sai-regmap, FSL_SAI_TCR2,
+  FSL_SAI_CR2_MSEL_MASK,
+  FSL_SAI_CR2_MSEL(sai-mclk_id[tx]));
+   regmap_update_bits(sai-regmap, FSL_SAI_TCR2,
+  FSL_SAI_CR2_DIV_MASK, savediv - 1);
+   }
+
+   dev_dbg(dai-dev, best fit: clock id=%d, div=%d, deviation =%d\n,
+   sai-mclk_id[tx], savediv, savesub);
+
+   return 0;
+}
+
 static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
@@ -297,6 +372,24 @@ static int fsl_sai_hw_params(struct snd_pcm_substream 
*substream,
unsigned int channels = params_channels(params);
u32 word_width = snd_pcm_format_width(params_format(params));
u32 val_cr4 = 0, val_cr5 = 0;
+   int ret;
+
+   if (!sai-is_slave_mode) {
+   ret = fsl_sai_set_bclk(cpu_dai, tx,
+   2 * word_width * params_rate(params));
+   if (ret)
+   return ret;
+
+   /* Do not enable the clock if it is already enabled */
+