Re: [alsa-devel][PATCH 1/3] ASoC: fsl_sai: add sai master mode support
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
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
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
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 */ +