diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts index f66adf66bce3..01b433777eaf 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_t309.dts @@ -300,7 +300,7 @@ aml-audio-card,dai-link@0 { format = "i2s"; mclk-fs = <256>; - //continuous-clock; + continuous-clock; //bitclock-inversion; //frame-inversion; /* master mode */ diff --git a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts index 3f76bb2366f8..2e4375d6e12e 100644 --- a/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts +++ b/arch/arm/boot/dts/amlogic/tl1_t962x2_x301.dts @@ -302,7 +302,7 @@ aml-audio-card,dai-link@0 { format = "i2s"; mclk-fs = <256>; - //continuous-clock; + continuous-clock; //bitclock-inversion; //frame-inversion; /* master mode */ diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index d0afc9a68e91..9cefe9264f2c 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -116,6 +116,9 @@ struct aml_tdm { /* virtual link for i2s to hdmitx */ int i2s2hdmitx; int acodec_adc; + uint last_mpll_freq; + uint last_mclk_freq; + uint last_fmt; }; static const struct snd_pcm_hardware aml_tdm_hardware = { @@ -368,33 +371,6 @@ struct snd_soc_platform_driver aml_tdm_platform = { .pcm_new = aml_tdm_new, }; -static int aml_dai_tdm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); - int ret; - - ret = clk_prepare_enable(p_tdm->mclk); - if (ret) { - pr_err("Can't enable mclk: %d\n", ret); - goto err; - } - - return ret; -err: - pr_err("failed enable clock\n"); - return ret; -} - -static void aml_dai_tdm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); - - /* disable clock and gate */ - clk_disable_unprepare(p_tdm->mclk); -} - static int aml_dai_tdm_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { @@ -770,6 +746,15 @@ static int aml_dai_tdm_hw_params(struct snd_pcm_substream *substream, rate * ratio * mux); } + if (!p_tdm->contns_clk && !IS_ERR(p_tdm->mclk)) { + pr_debug("%s(), enable mclk for %s", __func__, cpu_dai->name); + ret = clk_prepare_enable(p_tdm->mclk); + if (ret) { + pr_err("Can't enable mclk: %d\n", ret); + return ret; + } + } + return 0; } @@ -800,6 +785,12 @@ static int aml_dai_tdm_hw_free(struct snd_pcm_substream *substream, fr, p_tdm->samesource_sel); } + /* disable clock and gate */ + if (!p_tdm->contns_clk && !IS_ERR(p_tdm->mclk)) { + pr_info("%s(), disable mclk for %s", __func__, cpu_dai->name); + clk_disable_unprepare(p_tdm->mclk); + } + return 0; } @@ -809,6 +800,12 @@ static int aml_dai_set_tdm_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) pr_debug("asoc aml_dai_set_tdm_fmt, %#x, %p, id(%d), clksel(%d)\n", fmt, p_tdm, p_tdm->id, p_tdm->clk_sel); + if (p_tdm->last_fmt == fmt) { + pr_debug("%s(), fmt not change\n", __func__); + goto capture; + } else + p_tdm->last_fmt = fmt; + switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { case SND_SOC_DAIFMT_CONT: p_tdm->contns_clk = true; @@ -825,9 +822,9 @@ static int aml_dai_set_tdm_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) aml_tdm_set_format(p_tdm->actrl, &(p_tdm->setting), p_tdm->clk_sel, p_tdm->id, fmt, - cpu_dai->capture_active, - cpu_dai->playback_active); + 1, 1); +capture: /* update skew for ACODEC_ADC */ if (cpu_dai->capture_active && p_tdm->chipinfo @@ -863,6 +860,7 @@ static int aml_dai_set_tdm_sysclk(struct snd_soc_dai *cpu_dai, { struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); unsigned int ratio = aml_mpll_mclk_ratio(freq); + unsigned int mpll_freq = 0; p_tdm->setting.sysclk = freq; @@ -875,8 +873,20 @@ static int aml_dai_set_tdm_sysclk(struct snd_soc_dai *cpu_dai, ratio = 20; #endif - clk_set_rate(p_tdm->clk, freq * ratio); - clk_set_rate(p_tdm->mclk, freq); + mpll_freq = freq * ratio; + if (mpll_freq != p_tdm->last_mpll_freq) { + clk_set_rate(p_tdm->clk, mpll_freq); + p_tdm->last_mpll_freq = mpll_freq; + } else { + pr_debug("%s(), mpll no change, keep clk\n", __func__); + } + + if (freq != p_tdm->last_mclk_freq) { + clk_set_rate(p_tdm->mclk, freq); + p_tdm->last_mclk_freq = freq; + } else { + pr_debug("%s(), mclk no change, keep clk\n", __func__); + } pr_debug("set mclk:%d, mpll:%d, get mclk:%lu, mpll:%lu\n", freq, @@ -1051,9 +1061,22 @@ static int aml_dai_tdm_remove(struct snd_soc_dai *cpu_dai) return 0; } +static int aml_dai_tdm_mute_stream(struct snd_soc_dai *cpu_dai, + int mute, int stream) +{ + struct aml_tdm *p_tdm = snd_soc_dai_get_drvdata(cpu_dai); + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + pr_debug("tdm playback mute: %d\n", mute); + aml_tdm_mute_playback(p_tdm->actrl, p_tdm->id, mute); + } else if (stream == SNDRV_PCM_STREAM_CAPTURE) { + pr_debug("tdm capture mute: %d\n", mute); + aml_tdm_mute_capture(p_tdm->actrl, p_tdm->id, mute); + } + return 0; +} + static struct snd_soc_dai_ops aml_dai_tdm_ops = { - .startup = aml_dai_tdm_startup, - .shutdown = aml_dai_tdm_shutdown, .prepare = aml_dai_tdm_prepare, .trigger = aml_dai_tdm_trigger, .hw_params = aml_dai_tdm_hw_params, @@ -1063,6 +1086,7 @@ static struct snd_soc_dai_ops aml_dai_tdm_ops = { .set_bclk_ratio = aml_dai_set_bclk_ratio, .set_clkdiv = aml_dai_set_clkdiv, .set_tdm_slot = aml_dai_set_tdm_slot, + .mute_stream = aml_dai_tdm_mute_stream, }; #define AML_DAI_TDM_RATES (SNDRV_PCM_RATE_8000_192000) diff --git a/sound/soc/amlogic/auge/tdm_hw.c b/sound/soc/amlogic/auge/tdm_hw.c index 9f558b50ab43..f8f89bc40264 100644 --- a/sound/soc/amlogic/auge/tdm_hw.c +++ b/sound/soc/amlogic/auge/tdm_hw.c @@ -188,6 +188,72 @@ void aml_tdm_fifo_ctrl( } +static void aml_clk_set_tdmout_by_id( + struct aml_audio_controller *actrl, + unsigned int tdm_index, + unsigned int sclk_sel, + unsigned int lrclk_sel, + bool sclk_ws_inv, + bool is_master, + bool binv) +{ + unsigned int val_sclk_ws_inv = 0; + unsigned int reg = EE_AUDIO_CLK_TDMOUT_A_CTRL + tdm_index; + + /* This is just a copy from previous setting. WHY??? */ + val_sclk_ws_inv = sclk_ws_inv && is_master; + if (val_sclk_ws_inv) + aml_audiobus_update_bits(actrl, reg, + 0x3<<30|1<<28|0xf<<24|0xf<<20, + 0x3<<30|val_sclk_ws_inv<<28| + sclk_sel<<24|lrclk_sel<<20); + else + aml_audiobus_update_bits(actrl, reg, + 0x3<<30|1<<29|0xf<<24|0xf<<20, + 0x3<<30|binv<<29| + sclk_sel<<24|lrclk_sel<<20); +} + +static void aml_clk_set_tdmin_by_id( + struct aml_audio_controller *actrl, + unsigned int tdm_index, + unsigned int sclk_sel, + unsigned int lrclk_sel) +{ + unsigned int reg = + EE_AUDIO_CLK_TDMIN_A_CTRL + tdm_index; + aml_audiobus_update_bits(actrl, + reg, + 0xff<<20, + sclk_sel<<24|lrclk_sel<<20); +} + +static void aml_tdmout_invert_lrclk( + struct aml_audio_controller *actrl, + unsigned int tdm_index, + bool finv) +{ + unsigned int off_set = + EE_AUDIO_TDMOUT_B_CTRL1 - EE_AUDIO_TDMOUT_A_CTRL1; + unsigned int reg_out = + EE_AUDIO_TDMOUT_A_CTRL1 + off_set * tdm_index; + aml_audiobus_update_bits(actrl, + reg_out, 0x1<<28, finv<<28); +} + +static void aml_tdmout_bclk_skew( + struct aml_audio_controller *actrl, + unsigned int tdm_index, + unsigned int bclkout_skew) +{ + unsigned int off_set = + EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0; + unsigned int reg_out = + EE_AUDIO_TDMOUT_A_CTRL0 + off_set * tdm_index; + aml_audiobus_update_bits(actrl, + reg_out, 0x1f<<15, bclkout_skew<<15); +} + void aml_tdm_set_format( struct aml_audio_controller *actrl, struct pcm_setting *p_config, @@ -223,24 +289,7 @@ void aml_tdm_set_format( default: return; } - - //TODO: clk tree - reg_out = EE_AUDIO_CLK_TDMOUT_A_CTRL + id; - reg_in = EE_AUDIO_CLK_TDMIN_A_CTRL + id; - aml_audiobus_update_bits(actrl, - reg_out, - 0xff<<20, - valb<<24|valf<<20); - aml_audiobus_update_bits(actrl, - reg_in, - 0xff<<20, - valb<<24|valf<<20); - - if (p_config->sclk_ws_inv) - aml_audiobus_update_bits(actrl, - reg_out, - 1 << 28, - 0 << 28); + aml_clk_set_tdmin_by_id(actrl, id, valb, valf); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -355,27 +404,11 @@ void aml_tdm_set_format( /* TDM out */ if (playback_active) { - - reg_out = EE_AUDIO_CLK_TDMOUT_A_CTRL + id; - aml_audiobus_update_bits(actrl, reg_out, - 0x3<<30, 0x3<<30); - - if (p_config->sclk_ws_inv && master_mode) - aml_audiobus_update_bits(actrl, reg_out, - 0x1 << 28, - 0x1 << 28); - else - aml_audiobus_update_bits(actrl, reg_out, - 0x1<<29, binv<<29); - - off_set = EE_AUDIO_TDMOUT_B_CTRL1 - EE_AUDIO_TDMOUT_A_CTRL1; - reg_out = EE_AUDIO_TDMOUT_A_CTRL1 + off_set * id; - aml_audiobus_update_bits(actrl, reg_out, 0x1<<28, finv<<28); - - off_set = EE_AUDIO_TDMOUT_B_CTRL0 - EE_AUDIO_TDMOUT_A_CTRL0; - reg_out = EE_AUDIO_TDMOUT_A_CTRL0 + off_set * id; - aml_audiobus_update_bits(actrl, reg_out, - 0x1f<<15, bclkout_skew<<15); + aml_clk_set_tdmout_by_id(actrl, + id, valb, valf, + p_config->sclk_ws_inv, master_mode, binv); + aml_tdmout_invert_lrclk(actrl, id, finv); + aml_tdmout_bclk_skew(actrl, id, bclkout_skew); } /* TDM in */ @@ -660,3 +693,44 @@ void i2s_to_hdmitx_ctrl(int tdm_index) | tdm_index << 4 /* Bclk_sel */ ); } + +void aml_tdm_mute_playback( + struct aml_audio_controller *actrl, + int tdm_index, + bool mute) +{ + unsigned int offset, reg; + unsigned int mute_mask = 0xffffffff; + unsigned int mute_val = 0; + int i = 0, lanes = 4; + + if (mute) + mute_val = 0xffffffff; + + offset = EE_AUDIO_TDMOUT_B_MUTE0 + - EE_AUDIO_TDMOUT_A_MUTE0; + reg = EE_AUDIO_TDMOUT_A_MUTE0 + offset * tdm_index; + for (i = 0; i < lanes; i++) + aml_audiobus_update_bits(actrl, reg + i, mute_mask, mute_val); +} + +void aml_tdm_mute_capture( + struct aml_audio_controller *actrl, + int tdm_index, + bool mute) +{ + unsigned int offset, reg; + unsigned int mute_mask = 0xffffffff; + unsigned int mute_val = 0; + int i = 0, lanes = 4; + + if (mute) + mute_val = 0xffffffff; + + offset = EE_AUDIO_TDMIN_B_MUTE0 + - EE_AUDIO_TDMIN_A_MUTE0; + reg = EE_AUDIO_TDMIN_A_MUTE0 + offset * tdm_index; + for (i = 0; i < lanes; i++) + aml_audiobus_update_bits(actrl, reg + i, mute_mask, mute_val); +} + diff --git a/sound/soc/amlogic/auge/tdm_hw.h b/sound/soc/amlogic/auge/tdm_hw.h index b70036583d5e..85fe6303434f 100644 --- a/sound/soc/amlogic/auge/tdm_hw.h +++ b/sound/soc/amlogic/auge/tdm_hw.h @@ -142,4 +142,12 @@ extern void aml_tdm_clk_pad_select( int tdm_index, int clk_sel); extern void i2s_to_hdmitx_ctrl(int tdm_index); +void aml_tdm_mute_playback( + struct aml_audio_controller *actrl, + int index, + bool mute); +void aml_tdm_mute_capture( + struct aml_audio_controller *actrl, + int tdm_index, + bool mute); #endif