diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-08-12 16:25:00 -0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2019-08-12 16:25:00 -0300 |
commit | 272172bd418cc32aa466588150c8001bc229c712 (patch) | |
tree | f529a66933e79ba1f3753e8185112538e861c967 /sound/soc/codecs/cs42xx8.c | |
parent | 7f06d0aa530cc61cb5e048d4eb34921dee12058a (diff) | |
parent | d45331b00ddb179e291766617259261c112db872 (diff) |
Merge remote-tracking branch 'torvalds/master' into perf/core
To get closer to upstream and check if we need to sync more UAPI
headers, pick up fixes for libbpf that prevent perf's container tests
from completing successfuly, etc.
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'sound/soc/codecs/cs42xx8.c')
-rw-r--r-- | sound/soc/codecs/cs42xx8.c | 116 |
1 files changed, 97 insertions, 19 deletions
diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 6203f54d9f25..5b049fcdba20 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -47,6 +47,7 @@ struct cs42xx8_priv { unsigned long sysclk; u32 tx_channels; struct gpio_desc *gpiod_reset; + u32 rate[2]; }; /* -127.5dB to 0dB with step of 0.5dB */ @@ -176,21 +177,27 @@ static const struct snd_soc_dapm_route cs42xx8_adc3_dapm_routes[] = { }; struct cs42xx8_ratios { - unsigned int ratio; - unsigned char speed; - unsigned char mclk; + unsigned int mfreq; + unsigned int min_mclk; + unsigned int max_mclk; + unsigned int ratio[3]; }; +/* + * According to reference mannual, define the cs42xx8_ratio struct + * MFreq2 | MFreq1 | MFreq0 | Description | SSM | DSM | QSM | + * 0 | 0 | 0 |1.029MHz to 12.8MHz | 256 | 128 | 64 | + * 0 | 0 | 1 |1.536MHz to 19.2MHz | 384 | 192 | 96 | + * 0 | 1 | 0 |2.048MHz to 25.6MHz | 512 | 256 | 128 | + * 0 | 1 | 1 |3.072MHz to 38.4MHz | 768 | 384 | 192 | + * 1 | x | x |4.096MHz to 51.2MHz |1024 | 512 | 256 | + */ static const struct cs42xx8_ratios cs42xx8_ratios[] = { - { 64, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_256(4) }, - { 96, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_384(4) }, - { 128, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_512(4) }, - { 192, CS42XX8_FM_QUAD, CS42XX8_FUNCMOD_MFREQ_768(4) }, - { 256, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_256(1) }, - { 384, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_384(1) }, - { 512, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_512(1) }, - { 768, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_768(1) }, - { 1024, CS42XX8_FM_SINGLE, CS42XX8_FUNCMOD_MFREQ_1024(1) } + { 0, 1029000, 12800000, {256, 128, 64} }, + { 2, 1536000, 19200000, {384, 192, 96} }, + { 4, 2048000, 25600000, {512, 256, 128} }, + { 6, 3072000, 38400000, {768, 384, 192} }, + { 8, 4096000, 51200000, {1024, 512, 256} }, }; static int cs42xx8_set_dai_sysclk(struct snd_soc_dai *codec_dai, @@ -257,14 +264,68 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; - u32 ratio = cs42xx8->sysclk / params_rate(params); - u32 i, fm, val, mask; + u32 ratio[2]; + u32 rate[2]; + u32 fm[2]; + u32 i, val, mask; + bool condition1, condition2; if (tx) cs42xx8->tx_channels = params_channels(params); + rate[tx] = params_rate(params); + rate[!tx] = cs42xx8->rate[!tx]; + + ratio[tx] = rate[tx] > 0 ? cs42xx8->sysclk / rate[tx] : 0; + ratio[!tx] = rate[!tx] > 0 ? cs42xx8->sysclk / rate[!tx] : 0; + + /* Get functional mode for tx and rx according to rate */ + for (i = 0; i < 2; i++) { + if (cs42xx8->slave_mode) { + fm[i] = CS42XX8_FM_AUTO; + } else { + if (rate[i] < 50000) { + fm[i] = CS42XX8_FM_SINGLE; + } else if (rate[i] > 50000 && rate[i] < 100000) { + fm[i] = CS42XX8_FM_DOUBLE; + } else if (rate[i] > 100000 && rate[i] < 200000) { + fm[i] = CS42XX8_FM_QUAD; + } else { + dev_err(component->dev, + "unsupported sample rate\n"); + return -EINVAL; + } + } + } + for (i = 0; i < ARRAY_SIZE(cs42xx8_ratios); i++) { - if (cs42xx8_ratios[i].ratio == ratio) + /* Is the ratio[tx] valid ? */ + condition1 = ((fm[tx] == CS42XX8_FM_AUTO) ? + (cs42xx8_ratios[i].ratio[0] == ratio[tx] || + cs42xx8_ratios[i].ratio[1] == ratio[tx] || + cs42xx8_ratios[i].ratio[2] == ratio[tx]) : + (cs42xx8_ratios[i].ratio[fm[tx]] == ratio[tx])) && + cs42xx8->sysclk >= cs42xx8_ratios[i].min_mclk && + cs42xx8->sysclk <= cs42xx8_ratios[i].max_mclk; + + if (!ratio[tx]) + condition1 = true; + + /* Is the ratio[!tx] valid ? */ + condition2 = ((fm[!tx] == CS42XX8_FM_AUTO) ? + (cs42xx8_ratios[i].ratio[0] == ratio[!tx] || + cs42xx8_ratios[i].ratio[1] == ratio[!tx] || + cs42xx8_ratios[i].ratio[2] == ratio[!tx]) : + (cs42xx8_ratios[i].ratio[fm[!tx]] == ratio[!tx])); + + if (!ratio[!tx]) + condition2 = true; + + /* + * Both ratio[tx] and ratio[!tx] is valid, then we get + * a proper MFreq. + */ + if (condition1 && condition2) break; } @@ -273,15 +334,31 @@ static int cs42xx8_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - mask = CS42XX8_FUNCMOD_MFREQ_MASK; - val = cs42xx8_ratios[i].mclk; + cs42xx8->rate[tx] = params_rate(params); - fm = cs42xx8->slave_mode ? CS42XX8_FM_AUTO : cs42xx8_ratios[i].speed; + mask = CS42XX8_FUNCMOD_MFREQ_MASK; + val = cs42xx8_ratios[i].mfreq; regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, CS42XX8_FUNCMOD_xC_FM_MASK(tx) | mask, - CS42XX8_FUNCMOD_xC_FM(tx, fm) | val); + CS42XX8_FUNCMOD_xC_FM(tx, fm[tx]) | val); + + return 0; +} + +static int cs42xx8_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct cs42xx8_priv *cs42xx8 = snd_soc_component_get_drvdata(component); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + /* Clear stored rate */ + cs42xx8->rate[tx] = 0; + + regmap_update_bits(cs42xx8->regmap, CS42XX8_FUNCMOD, + CS42XX8_FUNCMOD_xC_FM_MASK(tx), + CS42XX8_FUNCMOD_xC_FM(tx, CS42XX8_FM_AUTO)); return 0; } @@ -302,6 +379,7 @@ static const struct snd_soc_dai_ops cs42xx8_dai_ops = { .set_fmt = cs42xx8_set_dai_fmt, .set_sysclk = cs42xx8_set_dai_sysclk, .hw_params = cs42xx8_hw_params, + .hw_free = cs42xx8_hw_free, .digital_mute = cs42xx8_digital_mute, }; |