staticint aiu_encoder_i2s_set_legacy_div(struct snd_soc_component *component, struct snd_pcm_hw_params *params, unsignedint bs)
{ switch (bs) { case 1: case 2: case 4: case 8: /* These are the only valid legacy dividers */ break;
staticint aiu_encoder_i2s_set_more_div(struct snd_soc_component *component, struct snd_pcm_hw_params *params, unsignedint bs)
{ /* * NOTE: this HW is odd. * In most configuration, the i2s divider is 'mclk / blck'. * However, in 16 bits - 8ch mode, this factor needs to be * increased by 50% to get the correct output rate. * No idea why !
*/ if (params_width(params) == 16 && params_channels(params) == 8) { if (bs % 2) {
dev_err(component->dev, "Cannot increase i2s divider by 50%%\n"); return -EINVAL;
}
bs += bs / 2;
}
/* Use CLK_MORE for mclk to bclk divider */
snd_soc_component_update_bits(component, AIU_CLK_CTRL,
AIU_CLK_CTRL_I2S_DIV,
FIELD_PREP(AIU_CLK_CTRL_I2S_DIV, 0));
/* Get the oversampling factor */
fs = DIV_ROUND_CLOSEST(clk_get_rate(aiu->i2s.clks[MCLK].clk), srate);
if (fs % 64) return -EINVAL;
/* Send data MSB first */
snd_soc_component_update_bits(component, AIU_I2S_DAC_CFG,
AIU_I2S_DAC_CFG_MSB_FIRST,
AIU_I2S_DAC_CFG_MSB_FIRST);
/* Set bclk to lrlck ratio */
snd_soc_component_update_bits(component, AIU_CODEC_DAC_LRCLK_CTRL,
AIU_CODEC_DAC_LRCLK_CTRL_DIV,
FIELD_PREP(AIU_CODEC_DAC_LRCLK_CTRL_DIV,
64 - 1));
bs = fs / 64;
if (aiu->platform->has_clk_ctrl_more_i2s_div)
ret = aiu_encoder_i2s_set_more_div(component, params, bs); else
ret = aiu_encoder_i2s_set_legacy_div(component, params, bs);
if (ret) return ret;
/* Make sure amclk is used for HDMI i2s as well */
snd_soc_component_update_bits(component, AIU_CLK_CTRL_MORE,
AIU_CLK_CTRL_MORE_HDMI_AMCLK,
AIU_CLK_CTRL_MORE_HDMI_AMCLK);
/* Only CPU Master / Codec Slave supported ATM */ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_BP_FP) return -EINVAL;
if (inv == SND_SOC_DAIFMT_NB_IF ||
inv == SND_SOC_DAIFMT_IB_IF)
val |= AIU_CLK_CTRL_LRCLK_INVERT;
/* * The SoC changes data on the rising edge of the bitclock * so an inversion of the bitclock is required in normal mode
*/ if (inv == SND_SOC_DAIFMT_NB_NF ||
inv == SND_SOC_DAIFMT_NB_IF)
val |= AIU_CLK_CTRL_AOCLK_INVERT;
/* Signal skew */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: /* Invert sample clock for i2s */
val ^= AIU_CLK_CTRL_LRCLK_INVERT;
skew = 1; break; case SND_SOC_DAIFMT_LEFT_J:
skew = 0; break; default: return -EINVAL;
}
/* Make sure the encoder gets either 2 or 8 channels */
ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
SNDRV_PCM_HW_PARAM_CHANNELS,
&hw_channel_constraints); if (ret) {
dev_err(dai->dev, "adding channels constraints failed\n"); return ret;
}
ret = clk_bulk_prepare_enable(aiu->i2s.clk_num, aiu->i2s.clks); if (ret)
dev_err(dai->dev, "failed to enable i2s clocks\n");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.