From ed70f3a264e9f746eaf17c96ccc4c9b7eda742dc Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 4 Jun 2014 10:11:06 +0100 Subject: ASoC: arizona: Implement TDM support for Arizona devices Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 78 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 6 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 29e198f..e77f61c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1185,7 +1185,10 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, int base = dai->driver->base; const int *rates; int i, ret, val; + int channels = params_channels(params); int chan_limit = arizona->pdata.max_channels_clocked[dai->id - 1]; + 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; if (params_rate(params) % 8000) @@ -1193,18 +1196,27 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, else rates = &arizona_48k_bclk_rates[0]; - bclk_target = snd_soc_params_to_bclk(params); - if (chan_limit && chan_limit < params_channels(params)) { + if (tdm_slots) { + arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", + tdm_slots, tdm_width); + bclk_target = tdm_slots * tdm_width * params_rate(params); + channels = tdm_slots; + } else { + bclk_target = snd_soc_params_to_bclk(params); + } + + if (chan_limit && chan_limit < channels) { arizona_aif_dbg(dai, "Limiting to %d channels\n", chan_limit); - bclk_target /= params_channels(params); + bclk_target /= channels; bclk_target *= chan_limit; } - /* Force stereo for I2S mode */ + /* Force multiple of 2 channels for I2S mode */ val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); - if (params_channels(params) == 1 && (val & ARIZONA_AIF1_FMT_MASK)) { + if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) { arizona_aif_dbg(dai, "Forcing stereo mode\n"); - bclk_target *= 2; + bclk_target /= channels; + bclk_target *= channels + 1; } for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { @@ -1324,9 +1336,63 @@ static int arizona_set_tristate(struct snd_soc_dai *dai, int tristate) ARIZONA_AIF1_TRI, reg); } +static void arizona_set_channels_to_mask(struct snd_soc_dai *dai, + unsigned int base, + int channels, unsigned int mask) +{ + struct snd_soc_codec *codec = dai->codec; + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int slot, i; + + for (i = 0; i < channels; ++i) { + slot = ffs(mask) - 1; + if (slot < 0) + return; + + regmap_write(arizona->regmap, base + i, slot); + + mask &= ~(1 << slot); + } + + if (mask) + arizona_aif_warn(dai, "Too many channels in TDM mask\n"); +} + +static int arizona_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, + unsigned int rx_mask, int slots, int slot_width) +{ + struct snd_soc_codec *codec = dai->codec; + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + int base = dai->driver->base; + int rx_max_chan = dai->driver->playback.channels_max; + int tx_max_chan = dai->driver->capture.channels_max; + + /* Only support TDM for the physical AIFs */ + if (dai->id > ARIZONA_MAX_AIF) + return -ENOTSUPP; + + if (slots == 0) { + tx_mask = (1 << tx_max_chan) - 1; + rx_mask = (1 << rx_max_chan) - 1; + } + + arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_3, + tx_max_chan, tx_mask); + arizona_set_channels_to_mask(dai, base + ARIZONA_AIF_FRAME_CTRL_11, + rx_max_chan, rx_mask); + + arizona->tdm_width[dai->id - 1] = slot_width; + arizona->tdm_slots[dai->id - 1] = slots; + + return 0; +} + const struct snd_soc_dai_ops arizona_dai_ops = { .startup = arizona_startup, .set_fmt = arizona_set_fmt, + .set_tdm_slot = arizona_set_tdm_slot, .hw_params = arizona_hw_params, .set_sysclk = arizona_dai_set_sysclk, .set_tristate = arizona_set_tristate, -- cgit v1.1 From cc9e92431ee9c7fe974266e0e6533a1a68e45539 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 6 Jun 2014 14:14:05 +0100 Subject: ASoC: wm5102: Add controls to allow shaping of ultrasonic response Add controls to allow custom shaping of the ultrasonic response. This custom shaping can be turned on/off at runtime, although, it should be noted that settings will not affect a currently open audio stream, they will be applied when the next audio stream is started. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e77f61c..41b56ee 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1127,6 +1127,31 @@ static int arizona_startup(struct snd_pcm_substream *substream, constraint); } +static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, + unsigned int rate) +{ + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + struct reg_default dac_comp[] = { + { 0x80, 0x3 }, + { ARIZONA_DAC_COMP_1, 0 }, + { ARIZONA_DAC_COMP_2, 0 }, + { 0x80, 0x0 }, + }; + + mutex_lock(&codec->mutex); + + dac_comp[1].def = arizona->dac_comp_coeff; + if (rate >= 176400) + dac_comp[2].def = arizona->dac_comp_enabled; + + mutex_unlock(&codec->mutex); + + regmap_multi_reg_write(arizona->regmap, + dac_comp, + ARRAY_SIZE(dac_comp)); +} + static int arizona_hw_params_rate(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -1153,6 +1178,15 @@ static int arizona_hw_params_rate(struct snd_pcm_substream *substream, switch (dai_priv->clk) { case ARIZONA_CLK_SYSCLK: + switch (priv->arizona->type) { + case WM5102: + arizona_wm5102_set_dac_comp(codec, + params_rate(params)); + break; + default: + break; + } + snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, ARIZONA_SAMPLE_RATE_1_MASK, sr_val); if (base) -- cgit v1.1 From 4714bc015de147c2da5248762b2772c6dbf160eb Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:43 +0100 Subject: ASoC: arizona: Do not test ratio zero as it is not a valid setting Zero is not a valid FRATIO for the FLL, as such we shouldn't test it whilst refining the FRATIO. This patch does just that. Reported-by: Ryo Tsutsui Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 41b56ee..b03974e 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1585,7 +1585,7 @@ static int arizona_calc_fratio(struct arizona_fll *fll, } } - for (ratio = init_ratio - 1; ratio >= 0; ratio--) { + for (ratio = init_ratio - 1; ratio > 0; ratio--) { if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < Fref) break; -- cgit v1.1 From 29fee829408117624efcd478f6f228d77039b969 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:44 +0100 Subject: ASoC: arizona: Correct checking of FLL ratio limitations The check to ensure the Fref frequency is within the bounds for the current ratio, was placed in the wrong loop. The initial configuration will always be valid and the loop lowering the ratio will only reinforce this validity. The check should be on the loop increasing the ratio. This could on occasion cause an invalid ratio/Fref combination to be selected. Reported-by: Ryo Tsutsui Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index b03974e..4c4727f 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1578,6 +1578,10 @@ static int arizona_calc_fratio(struct arizona_fll *fll, while (div <= ARIZONA_FLL_MAX_REFDIV) { for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; ratio++) { + if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < + Fref) + break; + if (target % (ratio * Fref)) { cfg->refdiv = refdiv; cfg->fratio = ratio - 1; @@ -1586,10 +1590,6 @@ static int arizona_calc_fratio(struct arizona_fll *fll, } for (ratio = init_ratio - 1; ratio > 0; ratio--) { - if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < - Fref) - break; - if (target % (ratio * Fref)) { cfg->refdiv = refdiv; cfg->fratio = ratio - 1; -- cgit v1.1 From 35a730a0790b2a6535e0b4a964c6a8b2d27fa019 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:45 +0100 Subject: ASoC: arizona: Correct relationship between VCO corner and Fref When configuring the FLL we must ensure that the reference clock passed to the FLL is under a certain limit. This limit was specified incorrectly in the current code, this patch corrects this. Although the error will only be encountered in some edge cases. Reported-by: Ryo Tsutsui Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 4c4727f..6084af7 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1578,8 +1578,8 @@ static int arizona_calc_fratio(struct arizona_fll *fll, while (div <= ARIZONA_FLL_MAX_REFDIV) { for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; ratio++) { - if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < - Fref) + if ((ARIZONA_FLL_VCO_CORNER / 2) / + (fll->vco_mult * ratio) < Fref) break; if (target % (ratio * Fref)) { -- cgit v1.1 From 613124ce644c38857ef5780a96e6d400d6b11abd Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:46 +0100 Subject: ASoC: arizona: Coding standards, remove unneeded brackets Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 6084af7..0a417e8 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1868,11 +1868,10 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->sync_freq = Fref; fll->fout = Fout; - if (Fout) { + if (Fout) arizona_enable_fll(fll); - } else { + else arizona_disable_fll(fll); - } return 0; } -- cgit v1.1 From c393aca94f26e90290cd861743efbfbcd97c0316 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:47 +0100 Subject: ASoC: arizona: Correct return value of arizona_is_enabled_fll arizona_is_enabled_fll currently returns a bool, but can throw an error. The error will be basically ignored and we will treat the FLL as already on. This patch changes the return to be an int and adds error code to propagate the error up to the callback. Reported-by: Anil Kumar Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0a417e8..a6f09bb 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1716,7 +1716,7 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, ARIZONA_FLL1_CTRL_UPD | cfg->n); } -static bool arizona_is_enabled_fll(struct arizona_fll *fll) +static int arizona_is_enabled_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; unsigned int reg; @@ -1732,13 +1732,17 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) return reg & ARIZONA_FLL1_ENA; } -static void arizona_enable_fll(struct arizona_fll *fll) +static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; int ret; bool use_sync = false; + int already_enabled = arizona_is_enabled_fll(fll); struct arizona_fll_cfg cfg; + if (already_enabled < 0) + return already_enabled; + /* * If we have both REFCLK and SYNCCLK then enable both, * otherwise apply the SYNCCLK settings to REFCLK. @@ -1766,7 +1770,7 @@ static void arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_ENA, 0); } else { arizona_fll_err(fll, "No clocks provided\n"); - return; + return -EINVAL; } /* @@ -1781,7 +1785,7 @@ static void arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_BW, ARIZONA_FLL1_SYNC_BW); - if (!arizona_is_enabled_fll(fll)) + if (!already_enabled) pm_runtime_get(arizona->dev); /* Clear any pending completions */ @@ -1800,6 +1804,8 @@ static void arizona_enable_fll(struct arizona_fll *fll) msecs_to_jiffies(250)); if (ret == 0) arizona_fll_warn(fll, "Timed out waiting for lock\n"); + + return 0; } static void arizona_disable_fll(struct arizona_fll *fll) @@ -1821,7 +1827,7 @@ static void arizona_disable_fll(struct arizona_fll *fll) int arizona_set_fll_refclk(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - int ret; + int ret = 0; if (fll->ref_src == source && fll->ref_freq == Fref) return 0; @@ -1836,17 +1842,17 @@ int arizona_set_fll_refclk(struct arizona_fll *fll, int source, fll->ref_freq = Fref; if (fll->fout && Fref > 0) { - arizona_enable_fll(fll); + ret = arizona_enable_fll(fll); } - return 0; + return ret; } EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); int arizona_set_fll(struct arizona_fll *fll, int source, unsigned int Fref, unsigned int Fout) { - int ret; + int ret = 0; if (fll->sync_src == source && fll->sync_freq == Fref && fll->fout == Fout) @@ -1869,11 +1875,11 @@ int arizona_set_fll(struct arizona_fll *fll, int source, fll->fout = Fout; if (Fout) - arizona_enable_fll(fll); + ret = arizona_enable_fll(fll); else arizona_disable_fll(fll); - return 0; + return ret; } EXPORT_SYMBOL_GPL(arizona_set_fll); -- cgit v1.1 From 5e39a50bf8c644f2ef348037d3e3efdc03fa65b2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:48 +0100 Subject: ASoC: arizona: FLL freerun only required whilst disabling The FLL freerun is only required whilst we disable the FLL not the entire time the FLL is disabled. This patch moves the FLL freerun disable from the enable sequence to the disable sequence. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a6f09bb..7c362cb 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1792,8 +1792,6 @@ static int arizona_enable_fll(struct arizona_fll *fll) try_wait_for_completion(&fll->ok); regmap_update_bits_async(arizona->regmap, fll->base + 1, - ARIZONA_FLL1_FREERUN, 0); - regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) regmap_update_bits_async(arizona->regmap, fll->base + 0x11, @@ -1819,6 +1817,8 @@ static void arizona_disable_fll(struct arizona_fll *fll) ARIZONA_FLL1_ENA, 0, &change); regmap_update_bits(arizona->regmap, fll->base + 0x11, ARIZONA_FLL1_SYNC_ENA, 0); + regmap_update_bits_async(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, 0); if (change) pm_runtime_put_autosuspend(arizona->dev); -- cgit v1.1 From c8badda8eea6e9d142c8794519f6a57aa3ea3123 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Wed, 9 Jul 2014 17:41:49 +0100 Subject: ASoC: arizona: Update handling for input change on an active FLL Currently, the driver places no restrictions on changes that can be applied to an active FLL. However, it is only possible to change the input for an active FLL, to change the output the FLL should be stopped and then recofigured. This patch disallows changes in output frequency and adds some additional handling to ensure the output remains consistent across an input transition. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 7c362cb..be3657a 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1500,6 +1500,12 @@ static int arizona_validate_fll(struct arizona_fll *fll, { unsigned int Fvco_min; + if (fll->fout && Fout != fll->fout) { + arizona_fll_err(fll, + "Can't change output on active FLL\n"); + return -EINVAL; + } + if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { arizona_fll_err(fll, "Can't scale %dMHz in to <=13.5MHz\n", @@ -1743,6 +1749,15 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (already_enabled < 0) return already_enabled; + if (already_enabled) { + /* Facilitate smooth refclk across the transition */ + regmap_update_bits_async(fll->arizona->regmap, fll->base + 0x7, + ARIZONA_FLL1_GAIN_MASK, 0); + regmap_update_bits_async(fll->arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, + ARIZONA_FLL1_FREERUN); + } + /* * If we have both REFCLK and SYNCCLK then enable both, * otherwise apply the SYNCCLK settings to REFCLK. @@ -1798,6 +1813,10 @@ static int arizona_enable_fll(struct arizona_fll *fll) ARIZONA_FLL1_SYNC_ENA, ARIZONA_FLL1_SYNC_ENA); + if (already_enabled) + regmap_update_bits_async(arizona->regmap, fll->base + 1, + ARIZONA_FLL1_FREERUN, 0); + ret = wait_for_completion_timeout(&fll->ok, msecs_to_jiffies(250)); if (ret == 0) -- cgit v1.1 From bedd4b1993ecb7228f8e5d6673e25d4482bd302b Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 22 Jul 2014 11:42:06 +0100 Subject: ASoC: arizona: Disable AIF TX/RX before configuring it 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. Signed-off-by: Dimitris Papastamos Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 87 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 18 deletions(-) (limited to 'sound/soc/codecs/arizona.c') diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index be3657a..9a73068 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1209,6 +1209,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) @@ -1224,6 +1245,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]; @@ -1274,28 +1297,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) -- cgit v1.1