ASoC: arizona: Disable AIF TX/RX before configuring it
Subsystems (3)
PATCH 1/1 ASoC: arizona: Disable AIF TX/RX before configuring it
If we don't disable the AIF TX/RX then we may fall into a situation where the new AIF settings are ignored by the device. For example, this problem manifests when switching between different sample rates.
--- sound/soc/codecs/arizona.c | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-)
sound/soc/codecs/arizona.c +18 -2
@@ -1249,6 +1249,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,int tdm_width = arizona->tdm_width[dai->id -1 ];int tdm_slots = arizona->tdm_slots[dai->id -1 ];int bclk, lrclk, wl, frame, bclk_target; +unsigned int aif_tx_state, aif_rx_state;if (params_rate (params) %8000 ) rates = &arizona_44k1_bclk_rates[0 ];
@@ -1299,9 +1300,18 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, wl =snd_pcm_format_width (params_format (params)); frame = wl <<ARIZONA_AIF1TX_WL_SHIFT | wl; +/* Save AIF TX/RX state */ + aif_tx_state =snd_soc_read (codec, base +ARIZONA_AIF_TX_ENABLES ); + aif_rx_state =snd_soc_read (codec, base +ARIZONA_AIF_RX_ENABLES ); +/* Disable AIF TX/RX before configuring it */ +snd_soc_update_bits (codec, base +ARIZONA_AIF_TX_ENABLES , +0xff ,0x0 ); +snd_soc_update_bits (codec, base +ARIZONA_AIF_RX_ENABLES , +0xff ,0x0 ); + ret =arizona_hw_params_rate (substream, params, dai);if (ret !=0 ) -return ret; + goto restore_aif; regmap_update_bits_async(arizona->regmap, base + ARIZONA_AIF_BCLK_CTRL,
@@ -1320,7 +1330,13 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,ARIZONA_AIF1RX_WL_MASK | ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); -return 0 ; +restore_aif: +/* Restore AIF TX/RX state */ +snd_soc_update_bits (codec, base +ARIZONA_AIF_TX_ENABLES , +0xff , aif_tx_state); +snd_soc_update_bits (codec, base +ARIZONA_AIF_RX_ENABLES , +0xff , aif_rx_state); +return ret; }static const char *arizona_dai_clk_str (int clk_id)
Signature · 1 line
1.7.2.5
Mark Brown
maintainerQuoted 4 lines · Richard Fitzgerald
If we don't disable the AIF TX/RX then we may fall into a situation where the new AIF settings are ignored by the device. For example, this problem manifests when switching between different sample rates.
So, what this does is momentarily disable the AIF when reconfiguring. That will glitch any running audio, making me wonder if the driver shouldn't be returning an error or at least complaining if it has to reconfigure instead. What's the use case where this might get triggered?
Quoted 7 lines · Mark Brown
Quoted 4 lines · Richard Fitzgerald
If we don't disable the AIF TX/RX then we may fall into a situation where the new AIF settings are ignored by the device. For example, this problem manifests when switching between different sample rates.
Quoted 5 lines
So, what this does is momentarily disable the AIF when reconfiguring. That will glitch any running audio, making me wonder if the driver shouldn't be returning an error or at least complaining if it has to reconfigure instead. What's the use case where this might get triggered?
The case being fixed is like this:
aplay 48kHz.wav; aplay 96kHz.wav
The second open happens before pmdown_time so the AIF is still enabled. Writes to the AIF config registers only take effect if the AIF is disabled. Without this patch, the 96kHz.wav will play at 48kHz
At Mon, 21 Jul 2014 10:01:22 +0100,
Quoted 15 lines · Richard Fitzgerald
Quoted 7 lines · Mark Brown
Quoted 4 lines · Richard Fitzgerald
If we don't disable the AIF TX/RX then we may fall into a situation where the new AIF settings are ignored by the device. For example, this problem manifests when switching between different sample rates.
Quoted 5 lines
So, what this does is momentarily disable the AIF when reconfiguring. That will glitch any running audio, making me wonder if the driver shouldn't be returning an error or at least complaining if it has to reconfigure instead. What's the use case where this might get triggered?
Quoted 7 lines
The case being fixed is like this:
aplay 48kHz.wav; aplay 96kHz.wav
The second open happens before
pmdown_timeso the AIF is still enabled. Writes to the AIF config registers only take effect if the AIF is disabled. Without this patch, the 96kHz.wav will play at 48kHz
If the glitch really matters, the driver can minimize by checking the change of sample rate and doing temporary turn on/off only when required.
Takashi
Quoted 25 lines · Takashi Iwai
At Mon, 21 Jul 2014 10:01:22 +0100,
Quoted 15 lines · Richard Fitzgerald
Quoted 7 lines · Mark Brown
Quoted 4 lines · Richard Fitzgerald
If we don't disable the AIF TX/RX then we may fall into a situation where the new AIF settings are ignored by the device. For example, this problem manifests when switching between different sample rates.
Quoted 5 lines
So, what this does is momentarily disable the AIF when reconfiguring. That will glitch any running audio, making me wonder if the driver shouldn't be returning an error or at least complaining if it has to reconfigure instead. What's the use case where this might get triggered?
Quoted 7 lines
The case being fixed is like this:
aplay 48kHz.wav; aplay 96kHz.wav
The second open happens before
pmdown_timeso the AIF is still enabled. Writes to the AIF config registers only take effect if the AIF is disabled. Without this patch, the 96kHz.wav will play at 48kHz
Quoted 6 lines
If the glitch really matters, the driver can minimize by checking the change of sample rate and doing temporary turn on/off only when required.
Takashi
That's a fair point.
Mark Brown
maintainerQuoted 11 lines · Richard Fitzgerald
Quoted 9 lines · Takashi Iwai
Quoted 7 lines · Richard Fitzgerald
The case being fixed is like this:
aplay 48kHz.wav; aplay 96kHz.wav
The second open happens before
pmdown_timeso the AIF is still enabled. Writes to the AIF config registers only take effect if the AIF is disabled. Without this patch, the 96kHz.wav will play at 48kHz
Quoted 5 lines
Quoted 3 lines
If the glitch really matters, the driver can minimize by checking the change of sample rate and doing temporary turn on/off only when required.
That's a fair point.
The case I was particularly worrying about here was simultaneous playback and capture - we won't be changing rates here since these devices currently require symmetry which is enforced via constraints but we are likely to at least be starting multiple streams close to each other frequently.
PATCH v2 1/1 ASoC: arizona: Disable AIF TX/RX before configuring it
In reply to Richard FitzgeraldChanges to the AIF configuration registers only take effect when the AIF is disabled. If the configuration is being changed from the previous setup, temporarily disable the AIF.
--- sound/soc/codecs/arizona.c | 87 +++++++++++++++++++++++++++++++++++--------- 1 files changed, 69 insertions(+), 18 deletions(-)
sound/soc/codecs/arizona.c +69 -18
@@ -1234,6 +1234,27 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream,return 0 ; } +static bool arizona_aif_cfg_changed (struct snd_soc_codec *codec, +int base,int bclk,int lrclk,int frame) +{ +int val; + + val =snd_soc_read (codec, base +ARIZONA_AIF_BCLK_CTRL ); +if (bclk != (val &ARIZONA_AIF1_BCLK_FREQ_MASK )) +return true; + + val =snd_soc_read (codec, base +ARIZONA_AIF_TX_BCLK_RATE ); +if (lrclk != (val &ARIZONA_AIF1TX_BCPF_MASK )) +return true; + + val =snd_soc_read (codec, base +ARIZONA_AIF_FRAME_CTRL_1 ); +if (frame != (val & (ARIZONA_AIF1TX_WL_MASK | +ARIZONA_AIF1TX_SLOT_LEN_MASK ))) +return true; + +return false; +} +static int arizona_hw_params (struct snd_pcm_substream *substream,struct snd_pcm_hw_params *params,struct snd_soc_dai *dai)
@@ -1249,6 +1270,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,int tdm_width = arizona->tdm_width[dai->id -1 ];int tdm_slots = arizona->tdm_slots[dai->id -1 ];int bclk, lrclk, wl, frame, bclk_target; +bool reconfig; +unsigned int aif_tx_state, aif_rx_state;if (params_rate (params) %8000 ) rates = &arizona_44k1_bclk_rates[0 ];
@@ -1299,28 +1322,56 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, wl =snd_pcm_format_width (params_format (params)); frame = wl <<ARIZONA_AIF1TX_WL_SHIFT | wl; + reconfig =arizona_aif_cfg_changed (codec, base, bclk, lrclk, frame); + +if (reconfig) { +/* Save AIF TX/RX state */ + aif_tx_state =snd_soc_read (codec, + base +ARIZONA_AIF_TX_ENABLES ); + aif_rx_state =snd_soc_read (codec, + base +ARIZONA_AIF_RX_ENABLES ); +/* Disable AIF TX/RX before reconfiguring it */ +regmap_update_bits_async (arizona->regmap, + base +ARIZONA_AIF_TX_ENABLES ,0xff ,0x0 ); +regmap_update_bits (arizona->regmap, + base +ARIZONA_AIF_RX_ENABLES ,0xff ,0x0 ); + } + ret =arizona_hw_params_rate (substream, params, dai);if (ret !=0 ) -return ret; + goto restore_aif; -regmap_update_bits_async (arizona->regmap, - base +ARIZONA_AIF_BCLK_CTRL , -ARIZONA_AIF1_BCLK_FREQ_MASK , bclk); -regmap_update_bits_async (arizona->regmap, - base +ARIZONA_AIF_TX_BCLK_RATE , -ARIZONA_AIF1TX_BCPF_MASK , lrclk); -regmap_update_bits_async (arizona->regmap, - base +ARIZONA_AIF_RX_BCLK_RATE , -ARIZONA_AIF1RX_BCPF_MASK , lrclk); -regmap_update_bits_async (arizona->regmap, - base +ARIZONA_AIF_FRAME_CTRL_1 , -ARIZONA_AIF1TX_WL_MASK | -ARIZONA_AIF1TX_SLOT_LEN_MASK , frame); -regmap_update_bits (arizona->regmap, base +ARIZONA_AIF_FRAME_CTRL_2 , -ARIZONA_AIF1RX_WL_MASK | -ARIZONA_AIF1RX_SLOT_LEN_MASK , frame); +if (reconfig) { +regmap_update_bits_async (arizona->regmap, + base +ARIZONA_AIF_BCLK_CTRL , +ARIZONA_AIF1_BCLK_FREQ_MASK , bclk); +regmap_update_bits_async (arizona->regmap, + base +ARIZONA_AIF_TX_BCLK_RATE , +ARIZONA_AIF1TX_BCPF_MASK , lrclk); +regmap_update_bits_async (arizona->regmap, + base +ARIZONA_AIF_RX_BCLK_RATE , +ARIZONA_AIF1RX_BCPF_MASK , lrclk); +regmap_update_bits_async (arizona->regmap, + base +ARIZONA_AIF_FRAME_CTRL_1 , +ARIZONA_AIF1TX_WL_MASK | +ARIZONA_AIF1TX_SLOT_LEN_MASK , frame); +regmap_update_bits (arizona->regmap, + base +ARIZONA_AIF_FRAME_CTRL_2 , +ARIZONA_AIF1RX_WL_MASK | +ARIZONA_AIF1RX_SLOT_LEN_MASK , frame); + } -return 0 ; +restore_aif: +if (reconfig) { +/* Restore AIF TX/RX state */ +regmap_update_bits_async (arizona->regmap, + base +ARIZONA_AIF_TX_ENABLES , +0xff , aif_tx_state); +regmap_update_bits (arizona->regmap, + base +ARIZONA_AIF_RX_ENABLES , +0xff , aif_rx_state); + } +return ret; }static const char *arizona_dai_clk_str (int clk_id)
Signature · 1 line
1.7.2.5
Quoted 4 lines · Richard Fitzgerald
Changes to the AIF configuration registers only take effect when the AIF is disabled. If the configuration is being changed from the previous setup, temporarily disable the AIF.
Applied, thanks.