static void tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr, uint8_t *buf, size_t size) { reg_clear(priv, REG_DIP_IF_FLAGS, bit); reg_write_range(priv, addr, buf, size); reg_set(priv, REG_DIP_IF_FLAGS, bit); }
static void tda998x_write_if(struct tda998x_priv *priv, u8 bit, u16 addr, union hdmi_infoframe *frame) { u8 buf[32]; ssize_t len; len = hdmi_infoframe_pack(frame, buf, sizeof(buf)); if (len < 0) { dev_err(&priv->hdmi->dev, "hdmi_infoframe_pack() type=0x%02x failed: %zd\n", frame->any.type, len); return; } reg_clear(priv, REG_DIP_IF_FLAGS, bit); reg_write_range(priv, addr, buf, len); reg_set(priv, REG_DIP_IF_FLAGS, bit); }
static void tda998x_configure_audio(struct tda998x_priv *priv, struct drm_display_mode *mode, struct tda998x_encoder_params *p) { u8 buf[6], clksel_aip, clksel_fs, cts_n, adiv; u32 n; /* Enable audio ports */ reg_write(priv, REG_ENA_AP, p->audio_cfg); reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg); /* Set audio input source */ switch (p->audio_format) { case AFMT_SPDIF: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF); clksel_aip = AIP_CLKSEL_AIP_SPDIF; clksel_fs = AIP_CLKSEL_FS_FS64SPDIF; cts_n = CTS_N_M(3) | CTS_N_K(3); break; case AFMT_I2S: reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); clksel_aip = AIP_CLKSEL_AIP_I2S; clksel_fs = AIP_CLKSEL_FS_ACLK; cts_n = CTS_N_M(3) | CTS_N_K(3); break; default: BUG(); return; } reg_write(priv, REG_AIP_CLKSEL, clksel_aip); reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT | AIP_CNTRL_0_ACR_MAN); /* auto CTS */ reg_write(priv, REG_CTS_N, cts_n); /* * Audio input somehow depends on HDMI line rate which is * related to pixclk. Testing showed that modes with pixclk * >100MHz need a larger divider while <40MHz need the default. * There is no detailed info in the datasheet, so we just * assume 100MHz requires larger divider. */ adiv = AUDIO_DIV_SERCLK_8; if (mode->clock > 100000) adiv++; /* AUDIO_DIV_SERCLK_16 */ /* S/PDIF asks for a larger divider */ if (p->audio_format == AFMT_SPDIF) adiv++; /* AUDIO_DIV_SERCLK_16 or _32 */ reg_write(priv, REG_AUDIO_DIV, adiv); /* * This is the approximate value of N, which happens to be * the recommended values for non-coherent clocks. */ n = 128 * p->audio_sample_rate / 1000; /* Write the CTS and N values */ buf[0] = 0x44; buf[1] = 0x42; buf[2] = 0x01; buf[3] = n; buf[4] = n >> 8; buf[5] = n >> 16; reg_write_range(priv, REG_ACR_CTS_0, buf, 6); /* Set CTS clock reference */ reg_write(priv, REG_AIP_CLKSEL, clksel_aip | clksel_fs); /* Reset CTS generator */ reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS); /* Write the channel status */ buf[0] = IEC958_AES0_CON_NOT_COPYRIGHT; buf[1] = 0x00; buf[2] = IEC958_AES3_CON_FS_NOTID; buf[3] = IEC958_AES4_CON_ORIGFS_NOTID | IEC958_AES4_CON_MAX_WORDLEN_24; reg_write_range(priv, REG_CH_STAT_B(0), buf, 4); tda998x_audio_mute(priv, true); msleep(20); tda998x_audio_mute(priv, false); /* Write the audio information packet */ tda998x_write_aif(priv, p); }