[PATCH 10/10] drm/i2c: tda998x: fix some audio errors
Jean-Francois Moine
moinejf at free.fr
Wed Oct 23 03:42:04 EDT 2013
This patch fixes some audio errors:
- use constants
- set audio FIFO read latency to 'current'
- set a large audio divider which works with all input sample rates
- compute a CTS from the video clock
- use any frequency in the channel status
Signed-off-by: Jean-Francois Moine <moinejf at free.fr>
---
drivers/gpu/drm/i2c/tda998x_drv.c | 57 ++++++++++------------
1 file changed, 26 insertions(+), 31 deletions(-)
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index b0eecee..1887108 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -216,7 +216,12 @@ struct tda998x_priv {
# define AIP_CLKSEL_FS(x) (((x) & 3) << 0)
# define AIP_CLKSEL_CLK_POL(x) (((x) & 1) << 2)
# define AIP_CLKSEL_AIP(x) (((x) & 7) << 3)
-
+#define SEL_AIP_SPDIF 0
+#define SEL_AIP_I2S 1
+#define CLKPOLDSD_ACLK 0 /* same pol as ACLK */
+#define CLKPOLDSD_NACLK 1 /* inverted */
+#define CTSREF_ACLK 0 /* I2S */
+#define CTSREF_FS64SPDIF 2 /* spdif */
/* Page 02h: PLL settings */
#define REG_PLL_SERIAL_1 REG(0x02, 0x00) /* read/write */
@@ -281,6 +286,7 @@ struct tda998x_priv {
# define CA_I2S_CA_I2S(x) (((x) & 31) << 0)
# define CA_I2S_HBR_CHSTAT (1 << 6)
#define REG_LATENCY_RD REG(0x11, 0x04) /* read/write */
+# define LATENCY_CURRENT 0x80
#define REG_ACR_CTS_0 REG(0x11, 0x05) /* read/write */
#define REG_ACR_CTS_1 REG(0x11, 0x06) /* read/write */
#define REG_ACR_CTS_2 REG(0x11, 0x07) /* read/write */
@@ -717,8 +723,8 @@ static void
tda998x_configure_audio(struct tda998x_priv *priv,
struct drm_display_mode *mode, struct tda998x_encoder_params *p)
{
- uint8_t buf[6], clksel_aip, clksel_fs, ca_i2s, cts_n, adiv;
- int aclk, n;
+ uint8_t buf[6], clksel_aip, clksel_fs, cts_n;
+ int aclk, n, cts;
/* Enable audio ports */
reg_write(priv, REG_ENA_AP, priv->audio_ports);
@@ -726,42 +732,29 @@ tda998x_configure_audio(struct tda998x_priv *priv,
/* Set audio input source */
if (priv->audio == AUDIO_SPDIF) {
reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF);
- clksel_aip = AIP_CLKSEL_AIP(0);
- /* FS64SPDIF */
- clksel_fs = AIP_CLKSEL_FS(2);
+ clksel_aip = AIP_CLKSEL_AIP(SEL_AIP_SPDIF);
+ clksel_fs = AIP_CLKSEL_FS(CTSREF_FS64SPDIF);
aclk = 0x00; /* no clock */
cts_n = CTS_N_M(3) | CTS_N_K(3);
- ca_i2s = 0;
} else {
reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S);
- clksel_aip = AIP_CLKSEL_AIP(1);
- /* ACLK */
- clksel_fs = AIP_CLKSEL_FS(0);
+ clksel_aip = AIP_CLKSEL_AIP(SEL_AIP_I2S);
+ clksel_fs = AIP_CLKSEL_FS(CTSREF_ACLK);
aclk = 0x01; /* clock enable */
cts_n = CTS_N_M(3) | CTS_N_K(3);
- ca_i2s = CA_I2S_CA_I2S(0);
}
reg_write(priv, REG_AIP_CLKSEL, clksel_aip);
+ reg_write(priv, REG_LATENCY_RD, LATENCY_CURRENT);
reg_write(priv, REG_ENA_ACLK, aclk);
- reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT);
+ reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT |
/* Enable automatic CTS generation */
- reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_ACR_MAN);
+ AIP_CNTRL_0_ACR_MAN);
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.
- */
- if (mode->clock > 100000)
- adiv = AUDIO_DIV_SERCLK_16;
- else
- adiv = AUDIO_DIV_SERCLK_8;
- reg_write(priv, REG_AUDIO_DIV, adiv);
+ /* a large divider works for all input sample rates */
+ reg_write(priv, REG_AUDIO_DIV, AUDIO_DIV_SERCLK_32);
/*
* This is the approximate value of N, which happens to be
@@ -770,9 +763,10 @@ tda998x_configure_audio(struct tda998x_priv *priv,
n = 128 * AUDIO_SAMPLE; /* acr_n = 128 * sample_rate / 1000 */
/* Write the CTS and N values */
- buf[0] = 0x44;
- buf[1] = 0x42;
- buf[2] = 0x01;
+ cts = mode->clock;
+ buf[0] = cts;
+ buf[1] = cts >> 8;
+ buf[2] = cts >> 16;
buf[3] = n;
buf[4] = n >> 8;
buf[5] = n >> 16;
@@ -786,10 +780,11 @@ tda998x_configure_audio(struct tda998x_priv *priv,
reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
/* Write the channel status */
- buf[0] = 0x04;
+ buf[0] = (1 << 2); /* copyright unprotected */
buf[1] = 0x00;
- buf[2] = 0x00;
- buf[3] = 0xf1;
+ buf[2] = 1; /* freq not indicated */
+ buf[3] = (0 << 4) | /* orig freq = not indicated */
+ 1; /* max word length 24 bits */
reg_write_range(priv, REG_CH_STAT_B(0), buf, 4);
tda998x_audio_mute(priv, true);
--
Ken ar c'hentañ | ** Breizh ha Linux atav! **
Jef | http://moinejf.free.fr/
More information about the linux-arm-kernel
mailing list