My cpu dai driving the tda998x in master mode outputs SNDRV_PCM_FORMAT_S24_LE, i2s left justified, two channels:
[SNDRV_PCM_FORMAT_S24_LE] = { .width = 24, .phys = 32, .le = 1, .signd = 1, .silence = {}, }, This format has a sample width of 24 bits, but a physical size of 32 bits per channel. The redundant bits are padded with zeros. This gives a total frame width of 64 bits. According to the tda19988 datasheet, this format is supported: "Audio samples with a precision better than 24-bit are truncated to 24-bit. [...] If the input clock has a frequency of 64fs and is left justified or Philips, the audio word is truncated to 24-bit format and other bits padded with zeros." (tda19988 product datasheet Rev. 3 - 21 July 2011) However, supplying this format to the chip results in distorted audio. I noticed that the audio problem disappears when the CTS_N pre-divider is calculated from the physical width, _not_ the sample width. This patch adjusts the CTS_N calculation so that the audio distortion goes away. Caveats: - I am only capable of generating audio with a frame width of 64fs. So I cannot test if 32fs or 48fs audio formats still work. Such as S16_LE or S20_LE. - I have no access to a datasheet which accurately describes the CTS_N register. So I cannot check if my assumption is correct. Tested with an imx6 ssi. Cc: Peter Rosin <p...@axentia.se> Signed-off-by: Sven Van Asbroeck <thesve...@gmail.com> --- drivers/gpu/drm/i2c/tda998x_drv.c | 4 ++-- include/drm/i2c/tda998x.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index a7c39f39793f..ba9f55176e1b 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -893,7 +893,7 @@ 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->physical_width) { case 16: cts_n = CTS_N_M(3) | CTS_N_K(1); break; @@ -982,7 +982,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 = { - .sample_width = params->sample_width, + .physical_width = params->physical_width, .sample_rate = params->sample_rate, .cea = params->cea, }; diff --git a/include/drm/i2c/tda998x.h b/include/drm/i2c/tda998x.h index 3cb25ccbe5e6..7e9fddcc4ddd 100644 --- a/include/drm/i2c/tda998x.h +++ b/include/drm/i2c/tda998x.h @@ -14,7 +14,7 @@ enum { struct tda998x_audio_params { u8 config; u8 format; - unsigned sample_width; + unsigned int physical_width; unsigned sample_rate; struct hdmi_audio_infoframe cea; u8 status[5]; -- 2.17.1