It appears that TDA998x derives the CTS value using the supplied I2S bit clock (BCLK) rather than 128·fs. TDA998x uses two constants named m and k in the CTS generator such that we have this relationship between the source BCLK and the sink fs:
128·fs_sink = BCLK·m / k Where BCLK = bclk_ratio·fs_source. We have been lucky up to now that all users have scaled their bclk_ratio to match the sample width - for example, on Beagle Bone Black, with a 16-bit sample width, BCLK = 32·fs, which increases to 64·fs for 32-bit samples. 24-bit samples are sent as 32-bit. We are now starting to see users whose I2S blocks send at 64·fs for 16-bit samples, which means TDA998x now breaks. ASoC has a snd_soc_dai_set_bclk_ratio() call available which sets the ratio of BCLK to the sample rate. Implement support for this. Signed-off-by: Russell King <rmk+ker...@armlinux.org.uk> --- drivers/gpu/drm/i2c/tda998x_drv.c | 20 +++++++++++++------- include/drm/i2c/tda998x.h | 1 + 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 645d884fb9e8..f2d40235acf9 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -895,21 +895,26 @@ tda998x_configure_audio(struct tda998x_priv *priv, reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S); clksel_aip = AIP_CLKSEL_AIP_I2S; clksel_fs = AIP_CLKSEL_FS_ACLK; - switch (params->sample_width) { + switch (params->bclk_ratio) { case 16: + cts_n = CTS_N_M(3) | CTS_N_K(0); + break; + case 32: cts_n = CTS_N_M(3) | CTS_N_K(1); break; - case 18: - case 20: - case 24: + case 48: cts_n = CTS_N_M(3) | CTS_N_K(2); break; - default: - case 32: + case 64: cts_n = CTS_N_M(3) | CTS_N_K(3); break; + case 128: + cts_n = CTS_N_M(0) | CTS_N_K(0); + break; + default: + dev_err(&priv->hdmi->dev, "unsupported I2S bclk ratio\n"); + return -EINVAL; } - switch (params->format & AFMT_I2S_MASK) { case AFMT_I2S_LEFT_J: i2s_fmt = I2S_FORMAT_LEFT_J; @@ -997,6 +1002,7 @@ static int tda998x_audio_hw_params(struct device *dev, void *data, struct tda998x_priv *priv = dev_get_drvdata(dev); int i, ret; struct tda998x_audio_params audio = { + .bclk_ratio = daifmt->bclk_ratio, .sample_width = params->sample_width, .sample_rate = params->sample_rate, .cea = params->cea, diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h index b0864f0be017..4e0f0cd2d428 100644 --- a/include/drm/i2c/tda998x.h +++ b/include/drm/i2c/tda998x.h @@ -19,6 +19,7 @@ enum { struct tda998x_audio_params { u8 config; u8 format; + u8 bclk_ratio; unsigned sample_width; unsigned sample_rate; struct hdmi_audio_infoframe cea; -- 2.7.4 _______________________________________________ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel