diff options
Diffstat (limited to 'sound/soc/codecs/ak4458.c')
-rw-r--r-- | sound/soc/codecs/ak4458.c | 66 |
1 files changed, 46 insertions, 20 deletions
diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index 85a1d00894a9..29eb78702bf3 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -306,6 +306,20 @@ static const struct snd_soc_dapm_route ak4497_intercon[] = { }; +static int ak4458_get_tdm_mode(struct ak4458_priv *ak4458) +{ + switch (ak4458->slots * ak4458->slot_width) { + case 128: + return 1; + case 256: + return 2; + case 512: + return 3; + default: + return 0; + } +} + static int ak4458_rstn_control(struct snd_soc_component *component, int bit) { int ret; @@ -333,13 +347,16 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); int pcm_width = max(params_physical_width(params), ak4458->slot_width); - u8 format, dsdsel0, dsdsel1; - int nfs1, dsd_bclk; + u8 format, dsdsel0, dsdsel1, dchn; + int nfs1, dsd_bclk, ret, channels, channels_max; nfs1 = params_rate(params); ak4458->fs = nfs1; /* calculate bit clock */ + channels = params_channels(params); + channels_max = dai->driver->playback.channels_max; + switch (params_format(params)) { case SNDRV_PCM_FORMAT_DSD_U8: case SNDRV_PCM_FORMAT_DSD_U16_LE: @@ -419,8 +436,24 @@ static int ak4458_hw_params(struct snd_pcm_substream *substream, snd_soc_component_update_bits(component, AK4458_00_CONTROL1, AK4458_DIF_MASK, format); - ak4458_rstn_control(component, 0); - ak4458_rstn_control(component, 1); + /* + * Enable/disable Daisy Chain if in TDM mode and the number of played + * channels is bigger than the maximum supported number of channels + */ + dchn = ak4458_get_tdm_mode(ak4458) && + (ak4458->fmt == SND_SOC_DAIFMT_DSP_B) && + (channels > channels_max) ? AK4458_DCHAIN_MASK : 0; + + snd_soc_component_update_bits(component, AK4458_0B_CONTROL7, + AK4458_DCHAIN_MASK, dchn); + + ret = ak4458_rstn_control(component, 0); + if (ret) + return ret; + + ret = ak4458_rstn_control(component, 1); + if (ret) + return ret; return 0; } @@ -429,6 +462,7 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_component *component = dai->component; struct ak4458_priv *ak4458 = snd_soc_component_get_drvdata(component); + int ret; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: /* Slave Mode */ @@ -461,8 +495,13 @@ static int ak4458_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) ak4458->fmt == SND_SOC_DAIFMT_PDM ? AK4458_DP_MASK : 0); - ak4458_rstn_control(component, 0); - ak4458_rstn_control(component, 1); + ret = ak4458_rstn_control(component, 0); + if (ret) + return ret; + + ret = ak4458_rstn_control(component, 1); + if (ret) + return ret; return 0; } @@ -508,20 +547,7 @@ static int ak4458_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, ak4458->slots = slots; ak4458->slot_width = slot_width; - switch (slots * slot_width) { - case 128: - mode = AK4458_MODE_TDM128; - break; - case 256: - mode = AK4458_MODE_TDM256; - break; - case 512: - mode = AK4458_MODE_TDM512; - break; - default: - mode = AK4458_MODE_NORMAL; - break; - } + mode = ak4458_get_tdm_mode(ak4458) << AK4458_MODE_SHIFT; snd_soc_component_update_bits(component, AK4458_0A_CONTROL6, AK4458_MODE_MASK, |