From 672d95c8cf4517d236401e51f752a6d31832b8af Mon Sep 17 00:00:00 2001 From: Vlad Karpovich Date: Mon, 30 Jul 2018 16:17:05 -0500 Subject: [PATCH] ASoC: cs35l41: Change master clock rate if using SCLK This is a port of following cs35l36 change: From: Paul Handrigan Date: Mon, 12 Feb 2018 13:51:32 -0600 Subject: [PATCH] ASoC: cs35l36: Change master clock rate if using SCLK If the device is using SCLK for the master clock, it is possible for the SCLK rate to change if the master changes the format, sample rate, and number of channels. This patch will calculate the from those parameters if using SCLK. Mot-CRs-fixed: (CR): River: AoU bringup on Marley+Prince Change-Id: I6815a075884ded0ebd352fed14259b575ade51ef Signed-off-by: Vlad Karpovich Reviewed-on: https://gerrit.mot.com/1220283 Tested-by: Jira Key SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Reviewed-by: Konstantin Makariev Submit-Approved: Jira Key --- sound/soc/codecs/cs35l41.c | 131 ++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 51 deletions(-) diff --git a/sound/soc/codecs/cs35l41.c b/sound/soc/codecs/cs35l41.c index b0c870096aa6..5dc28f1b49d5 100644 --- a/sound/soc/codecs/cs35l41.c +++ b/sound/soc/codecs/cs35l41.c @@ -1049,57 +1049,6 @@ static const struct cs35l41_global_fs_config cs35l41_fs_rates[] = { { 32000, 0x13 }, }; -static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *dai) -{ - struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(dai->codec); - int i; - unsigned int rate = params_rate(params); - u8 asp_width, asp_wl; - - for (i = 0; i < ARRAY_SIZE(cs35l41_fs_rates); i++) { - if (rate == cs35l41_fs_rates[i].rate) - break; - } - regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL, - CS35L41_GLOBAL_FS_MASK, - cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT); - - asp_wl = params_width(params); - asp_width = params_physical_width(params); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, - CS35L41_ASP_WIDTH_RX_MASK, - asp_width << CS35L41_ASP_WIDTH_RX_SHIFT); - regmap_update_bits(cs35l41->regmap, CS35L41_SP_RX_WL, - CS35L41_ASP_RX_WL_MASK, - asp_wl << CS35L41_ASP_RX_WL_SHIFT); - if (cs35l41->i2s_mode || cs35l41->tdm_mode) { - regmap_update_bits(cs35l41->regmap, - CS35L41_SP_FRAME_RX_SLOT, - CS35L41_ASP_RX1_SLOT_MASK, - ((cs35l41->pdata.right_channel) ? 1 : 0) - << CS35L41_ASP_RX1_SLOT_SHIFT); - regmap_update_bits(cs35l41->regmap, - CS35L41_SP_FRAME_RX_SLOT, - CS35L41_ASP_RX2_SLOT_MASK, - ((cs35l41->pdata.right_channel) ? 0 : 1) - << CS35L41_ASP_RX2_SLOT_SHIFT); - } - } else { - regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, - CS35L41_ASP_WIDTH_TX_MASK, - asp_width << CS35L41_ASP_WIDTH_TX_SHIFT); - regmap_update_bits(cs35l41->regmap, CS35L41_SP_TX_WL, - CS35L41_ASP_TX_WL_MASK, - asp_wl << CS35L41_ASP_TX_WL_SHIFT); - } - - return 0; -} - static int cs35l41_get_clk_config(int freq) { int i; @@ -1139,6 +1088,8 @@ static int cs35l41_codec_set_sysclk(struct snd_soc_codec *codec, cs35l41->extclk_freq = freq; + dev_dbg(cs35l41->dev, "Set CODEC sysclk to %d\n", freq); + switch (clk_id) { case 0: cs35l41->clksrc = CS35L41_PLLSRC_SCLK; @@ -1203,9 +1154,87 @@ static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, if (clk_id == CS35L41_PLLSRC_SCLK) cs35l41->sclk = freq; + dev_dbg(cs35l41->dev, "Set DAI sysclk %d\n", freq); + return 0; } +static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(dai->codec); + struct snd_soc_codec *codec = dai->codec; + int i, ret; + unsigned int rate = params_rate(params); + u8 asp_width, asp_wl; + int sclk_rate = params_rate(params) * params_width(params) + * params_channels(params); + + if ((cs35l41->clksrc == CS35L41_PLLSRC_SCLK) && + (cs35l41->sclk != sclk_rate)) { + dev_dbg(cs35l41->dev, "Reset sclk rate to %d from %d\n", + sclk_rate, cs35l41->sclk); + dev_dbg(cs35l41->dev, "rate %d width %d channels %d\n", + params_rate(params), params_width(params), + params_channels(params)); + ret = cs35l41_codec_set_sysclk(codec, CS35L41_PLLSRC_SCLK, 0, + sclk_rate, 0); + if (ret != 0) { + dev_err(cs35l41->dev, "Can't set codec sysclk %d\n", + ret); + return ret; + } + ret = cs35l41_dai_set_sysclk(dai, + CS35L41_PLLSRC_SCLK, sclk_rate, 0); + if (ret != 0) { + dev_err(cs35l41->dev, "Can't set dai sysclk %d\n", ret); + return ret; + } + } + + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_rates); i++) { + if (rate == cs35l41_fs_rates[i].rate) + break; + } + regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL, + CS35L41_GLOBAL_FS_MASK, + cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT); + + asp_wl = params_width(params); + asp_width = params_physical_width(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_RX_MASK, + asp_width << CS35L41_ASP_WIDTH_RX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_RX_WL, + CS35L41_ASP_RX_WL_MASK, + asp_wl << CS35L41_ASP_RX_WL_SHIFT); + if (cs35l41->i2s_mode || cs35l41->tdm_mode) { + regmap_update_bits(cs35l41->regmap, + CS35L41_SP_FRAME_RX_SLOT, + CS35L41_ASP_RX1_SLOT_MASK, + ((cs35l41->pdata.right_channel) ? 1 : 0) + << CS35L41_ASP_RX1_SLOT_SHIFT); + regmap_update_bits(cs35l41->regmap, + CS35L41_SP_FRAME_RX_SLOT, + CS35L41_ASP_RX2_SLOT_MASK, + ((cs35l41->pdata.right_channel) ? 0 : 1) + << CS35L41_ASP_RX2_SLOT_SHIFT); + } + } else { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_TX_MASK, + asp_width << CS35L41_ASP_WIDTH_TX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_TX_WL, + CS35L41_ASP_TX_WL_MASK, + asp_wl << CS35L41_ASP_TX_WL_SHIFT); + } + + return ret; +} + static int cs35l41_boost_config(struct cs35l41_private *cs35l41, int boost_ind, int boost_cap, int boost_ipk) {