From b8db114aca7f066e87b2bcd0df5f3731b939ab53 Mon Sep 17 00:00:00 2001 From: Xing Wang Date: Mon, 24 Apr 2017 20:45:30 +0800 Subject: [PATCH] audio: fix pcm bclk PD#141217: fix pcm bclk following sample rate, pcm format and slot number Change-Id: I4e1547c6c7c133a46a8c8b9a9d595adb7aa2771c Signed-off-by: Xing Wang --- sound/soc/amlogic/aml_audio_hw_pcm.c | 97 +++++++++++++++++++++++------------- sound/soc/amlogic/aml_pcm_dai.c | 16 ++++-- 2 files changed, 73 insertions(+), 40 deletions(-) diff --git a/sound/soc/amlogic/aml_audio_hw_pcm.c b/sound/soc/amlogic/aml_audio_hw_pcm.c index 4844359..f6af298 100644 --- a/sound/soc/amlogic/aml_audio_hw_pcm.c +++ b/sound/soc/amlogic/aml_audio_hw_pcm.c @@ -36,7 +36,7 @@ static unsigned int pcmin_buffer_size; static unsigned int pcmout_buffer_addr; static unsigned int pcmout_buffer_size; -int valid_channel[] = { +static int valid_channel[] = { 0x1, /* slot number 1 */ 0x3, /* slot number 2 */ 0x7, /* slot number 3 */ @@ -55,6 +55,9 @@ int valid_channel[] = { 0xffff /* slot number 16 */ }; +/* counter for pcm clk used */ +static int aml_pcm_clk_count; + static uint32_t aml_read_cbus_bits(uint32_t reg, const uint32_t start, const uint32_t len) { @@ -117,11 +120,14 @@ RESET_FIFO: if (flag) { unsigned int pcm_mode = 1; - unsigned int valid_slot = - valid_channel[substream->runtime->channels - 1]; + unsigned int num_slot = substream->runtime->channels; + unsigned int valid_slot = valid_channel[num_slot - 1]; unsigned int max_bits = 0xf; unsigned int valid_bits = 0xf; + /* whatever pcm out is enable */ + aml_pcm_clk_count++; + switch (substream->runtime->format) { case SNDRV_PCM_FORMAT_S32_LE: pcm_mode = 3; @@ -218,7 +224,7 @@ RESET_FIFO: if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0xF; + slot_offset_s = num_slot - 1; bit_offset_e = 0; slot_offset_e = 0; } else { @@ -234,7 +240,7 @@ RESET_FIFO: case SNDRV_PCM_FORMAT_S32_LE: if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0x1F; + slot_offset_s = (num_slot << 1) - 1; bit_offset_e = 0; slot_offset_e = 0; } @@ -242,7 +248,7 @@ RESET_FIFO: case SNDRV_PCM_FORMAT_S24_LE: if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0x1F; + slot_offset_s = (num_slot << 1) - 8 - 1; bit_offset_e = 0; slot_offset_e = 0; } @@ -252,22 +258,31 @@ RESET_FIFO: case SNDRV_PCM_FORMAT_S8: if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0x7; - slot_offset_s = 0xF; + slot_offset_s = (num_slot >> 1) - 1; bit_offset_e = 0; slot_offset_e = 0; } break; } - aml_write_cbus(PCMOUT_CTRL2, - aml_read_cbus(PCMOUT_CTRL2) | + pr_info("pcm master in, pcm mode:%d, valid bits:0x%x, valid slot:0x%x\n", + pcm_mode, + valid_bits, + valid_slot); + + aml_write_cbus(PCMOUT_CTRL2, + /* underrun use mute constant */ + (0 << 29) | /* pcmo max slot number in one frame*/ - (0xF << 22) | + ((num_slot - 1) << 22) | /* pcmo max bit number in one slot*/ (valid_bits << 16) | (valid_slot << 0) - ); + ); aml_write_cbus(PCMOUT_CTRL1, - aml_read_cbus(PCMOUT_CTRL1) | + /* pcmo output data byte number. 00 : 8bits. + * 01: 16bits. 10: 24bits. 11: 32bits + */ + (pcm_mode << 30) | /* use posedge of PCM clock to output data*/ (0 << 28) | /* invert fs phase */ @@ -285,14 +300,12 @@ RESET_FIFO: /* fs_o end postion slot bit counter number.*/ (slot_offset_e << 0) ); - aml_write_cbus(PCMOUT_CTRL0, - aml_read_cbus(PCMOUT_CTRL0) | - (1 << 31) | /* enable */ - (1 << 29) /* master */ - ); + aml_cbus_update_bits(PCMOUT_CTRL0, 1 << 31, 1 << 31); + aml_cbus_update_bits(PCMOUT_CTRL0, 1 << 29, 1 << 29); } } else { - if (!pcm_out_is_enable()) { + aml_pcm_clk_count--; + if (aml_pcm_clk_count <= 0) { /* disable pcmout */ aml_cbus_update_bits(PCMOUT_CTRL0, 1 << 31, 0 << 31); } @@ -336,8 +349,8 @@ void pcm_in_enable(struct snd_pcm_substream *substream, int flag) if (flag) { unsigned int pcm_mode = 1; - unsigned int valid_slot = - valid_channel[substream->runtime->channels - 1]; + unsigned int num_slot = substream->runtime->channels; + unsigned int valid_slot = valid_channel[num_slot - 1]; unsigned int max_bits = 0xf; unsigned int valid_bits = 0xf; @@ -512,15 +525,15 @@ static void pcm_out_register_show(void) void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) { unsigned int pcm_mode = 1; - unsigned int valid_slot = - valid_channel[substream->runtime->channels - 1]; + unsigned int num_slot = substream->runtime->channels; + unsigned int valid_slot = valid_channel[num_slot - 1]; unsigned int valid_bits = 0xf; unsigned int dsp_mode = SND_SOC_DAIFMT_DSP_B; unsigned int bit_offset_s, slot_offset_s, bit_offset_e, slot_offset_e; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0xF; + slot_offset_s = num_slot - 1; bit_offset_e = 0; slot_offset_e = 0; } else { @@ -539,7 +552,7 @@ void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) valid_bits = 0x1f; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0x1F; + slot_offset_s = (num_slot << 1) - 1; bit_offset_e = 0; slot_offset_e = 0; } @@ -549,7 +562,7 @@ void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) valid_bits = 0x17; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0x17; + slot_offset_s = (num_slot << 1) - 8 - 1; bit_offset_e = 0; slot_offset_e = 0; } @@ -563,13 +576,18 @@ void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) valid_bits = 0x7; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0x7; - slot_offset_s = 0xF; + slot_offset_s = (num_slot >> 1) - 1; bit_offset_e = 0; slot_offset_e = 0; } break; } + pr_info("pcm master out, pcm mode:%d, valid bits:0x%x, valid slot:0x%x\n", + pcm_mode, + valid_bits, + valid_slot); + /* reset fifo */ aml_cbus_update_bits(AUDOUT_CTRL, 1 << 30, 1 << 30); aml_cbus_update_bits(AUDOUT_CTRL, 1 << 30, 1 << 30); @@ -630,13 +648,12 @@ void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) aml_write_cbus(PCMOUT_CTRL3, 0); /* mute constant */ /* pcmout control2 */ - /* FS * 16 * 16 = BCLK */ - /* FS * 32 * 16 = BCLK */ + /* FS * valid bit * slot num = BCLK */ aml_write_cbus(PCMOUT_CTRL2, /* underrun use mute constant */ (0 << 29) | /* pcmo max slot number in one frame */ - (0xF << 22) | + ((num_slot - 1) << 22) | /* pcmo max bit number in one slot */ (valid_bits << 16) | /* pcmo valid slot. each bit for one slot */ @@ -689,6 +706,14 @@ void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) /*slave mode, sync fs with frame slot counter.*/ (0 << 0) ); + + aml_pcm_clk_count++; + } else { + aml_pcm_clk_count--; + if (aml_pcm_clk_count <= 0) { + /* disable pcmout */ + aml_cbus_update_bits(PCMOUT_CTRL0, 1 << 31, 0 << 31); + } } pr_debug("PCMOUT %s\n", flag ? "enable" : "disable"); @@ -698,15 +723,15 @@ void pcm_master_out_enable(struct snd_pcm_substream *substream, int flag) void pcm_out_enable(struct snd_pcm_substream *substream, int flag) { unsigned int pcm_mode = 1; - unsigned int valid_slot = - valid_channel[substream->runtime->channels - 1]; + unsigned int num_slot = substream->runtime->channels; + unsigned int valid_slot = valid_channel[num_slot - 1]; unsigned int valid_bits = 0xf; unsigned int dsp_mode = SND_SOC_DAIFMT_DSP_A; unsigned int bit_offset_s, slot_offset_s, bit_offset_e, slot_offset_e; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0xF; + slot_offset_s = num_slot - 1; bit_offset_e = 0; slot_offset_e = 0; } else { @@ -725,7 +750,7 @@ void pcm_out_enable(struct snd_pcm_substream *substream, int flag) valid_bits = 0x1f; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0x1F; + slot_offset_s = (num_slot << 1) - 1; bit_offset_e = 0; slot_offset_e = 0; } @@ -735,7 +760,7 @@ void pcm_out_enable(struct snd_pcm_substream *substream, int flag) valid_bits = 0x1f; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0xF; - slot_offset_s = 0x1F; + slot_offset_s = (num_slot << 1) - 8 - 1; bit_offset_e = 0; slot_offset_e = 0; } @@ -749,14 +774,14 @@ void pcm_out_enable(struct snd_pcm_substream *substream, int flag) valid_bits = 0x7; if (dsp_mode == SND_SOC_DAIFMT_DSP_A) { bit_offset_s = 0x7; - slot_offset_s = 0xF; + slot_offset_s = (num_slot >> 1) - 1; bit_offset_e = 0; slot_offset_e = 0; } break; } - pr_debug("pcm out, pcm mode:%d, valid bits:%x, valid slot:%x\n", + pr_info("pcm out, pcm mode:%d, valid bits:0x%x, valid slot:0x%x\n", pcm_mode, valid_bits, valid_slot); diff --git a/sound/soc/amlogic/aml_pcm_dai.c b/sound/soc/amlogic/aml_pcm_dai.c index f89e3c8..1416c6d7b 100644 --- a/sound/soc/amlogic/aml_pcm_dai.c +++ b/sound/soc/amlogic/aml_pcm_dai.c @@ -92,17 +92,25 @@ static int aml_pcm_dai_prepare(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct aml_pcm_runtime_data *prtd = runtime->private_data; struct aml_pcm *pcm = snd_soc_dai_get_drvdata(dai); - int mclk_rate; + int mclk_rate, pcm_bit; pr_debug("***Entered %s\n", __func__); /* set bclk */ if (runtime->format == SNDRV_PCM_FORMAT_S32_LE) - mclk_rate = runtime->rate * PCM_32BIT_MCLK_RATIO_SR; + pcm_bit = 32; else if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) - mclk_rate = runtime->rate * PCM_24BIT_MCLK_RATIO_SR; + pcm_bit = 24; else - mclk_rate = runtime->rate * PCM_DEFAULT_MCLK_RATIO_SR; + pcm_bit = 16; + + mclk_rate = runtime->rate * pcm_bit * runtime->channels; + pr_info("%s rate:%d, bits:%d, channels:%d, mclk:%d\n", + __func__, + runtime->rate, + pcm_bit, + runtime->channels, + mclk_rate); aml_pcm_set_clk(pcm, mclk_rate); -- 2.7.4