summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@armlinux.org.uk>2019-03-01 11:07:19 +0000
committerRussell King <rmk+kernel@armlinux.org.uk>2020-08-04 17:42:05 +0100
commite02e7813df718e01d51de6e6cc8a760e786457bd (patch)
treeed9db4489c1512fc0f5ac168fd66feb583842b11
parentca3c771ddad0d254ff9cd20c2868a59186840372 (diff)
drm/i2c: tda998x: support for bclk_ratio via hdmi-codec hw_params
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r--drivers/gpu/drm/i2c/tda998x_drv.c57
1 files changed, 42 insertions, 15 deletions
diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c
index 9517f522dcb9..77787daab6d5 100644
--- a/drivers/gpu/drm/i2c/tda998x_drv.c
+++ b/drivers/gpu/drm/i2c/tda998x_drv.c
@@ -62,6 +62,7 @@ struct tda998x_priv {
u8 vip_cntrl_0;
u8 vip_cntrl_1;
u8 vip_cntrl_2;
+ u8 i2s_cts_n;
unsigned long tmds_clock;
struct tda998x_audio_settings audio;
@@ -961,25 +962,24 @@ static u8 tda998x_get_adiv(struct tda998x_priv *priv, unsigned int fs)
*
* Note: S/PDIF always uses a bclk_ratio of 64.
*/
-static int tda998x_derive_cts_n(struct tda998x_priv *priv,
- struct tda998x_audio_settings *settings,
+static int tda998x_derive_cts_n(struct tda998x_priv *priv, u8 *cts_n,
unsigned int ratio)
{
switch (ratio) {
case 16:
- settings->cts_n = CTS_N_M(3) | CTS_N_K(0);
+ *cts_n = CTS_N_M(3) | CTS_N_K(0);
break;
case 32:
- settings->cts_n = CTS_N_M(3) | CTS_N_K(1);
+ *cts_n = CTS_N_M(3) | CTS_N_K(1);
break;
case 48:
- settings->cts_n = CTS_N_M(3) | CTS_N_K(2);
+ *cts_n = CTS_N_M(3) | CTS_N_K(2);
break;
case 64:
- settings->cts_n = CTS_N_M(3) | CTS_N_K(3);
+ *cts_n = CTS_N_M(3) | CTS_N_K(3);
break;
case 128:
- settings->cts_n = CTS_N_M(0) | CTS_N_K(0);
+ *cts_n = CTS_N_M(0) | CTS_N_K(0);
break;
default:
dev_err(&priv->hdmi->dev, "unsupported bclk ratio %ufs\n",
@@ -1059,12 +1059,28 @@ static void tda998x_configure_audio(struct tda998x_priv *priv)
tda998x_write_aif(priv, &settings->cea);
}
+static int tda998x_audio_startup(struct device *dev, void *data)
+{
+ struct tda998x_priv *priv = dev_get_drvdata(dev);
+
+ priv->i2s_cts_n = 0xff;
+
+ return 0;
+}
+
+static int tda998x_audio_bclk_ratio(struct device *dev, void *data,
+ unsigned int ratio)
+{
+ struct tda998x_priv *priv = dev_get_drvdata(dev);
+
+ return tda998x_derive_cts_n(priv, &priv->i2s_cts_n, ratio);
+}
+
static int tda998x_audio_hw_params(struct device *dev, void *data,
struct hdmi_codec_daifmt *daifmt,
struct hdmi_codec_params *params)
{
struct tda998x_priv *priv = dev_get_drvdata(dev);
- unsigned int bclk_ratio;
bool spdif = daifmt->fmt == HDMI_SPDIF;
int ret;
struct tda998x_audio_settings audio = {
@@ -1107,10 +1123,19 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
if (ret < 0)
return ret;
- bclk_ratio = spdif ? 64 : params->sample_width * 2;
- ret = tda998x_derive_cts_n(priv, &audio, bclk_ratio);
- if (ret < 0)
- return ret;
+ if (spdif) {
+ tda998x_derive_cts_n(priv, &audio.cts_n, 64);
+ } else if (priv->i2s_cts_n != 0xff) {
+ audio.cts_n = priv->i2s_cts_n;
+ } else {
+ dev_warn_once(&priv->hdmi->dev,
+ "I2S bit clock ratio not set, defaulting to 2x sample_width.\n"
+ "Please call snd_soc_dai_set_bclk_ratio() for this codec.\n");
+ ret = tda998x_derive_cts_n(priv, &audio.cts_n,
+ params->sample_width * 2);
+ if (ret < 0)
+ return ret;
+ }
mutex_lock(&priv->audio_mutex);
priv->audio = audio;
@@ -1160,6 +1185,8 @@ static int tda998x_audio_get_eld(struct device *dev, void *data,
}
static const struct hdmi_codec_ops audio_codec_ops = {
+ .audio_startup = tda998x_audio_startup,
+ .set_bclk_ratio = tda998x_audio_bclk_ratio,
.hw_params = tda998x_audio_hw_params,
.audio_shutdown = tda998x_audio_shutdown,
.digital_mute = tda998x_audio_digital_mute,
@@ -1757,7 +1784,7 @@ static int tda998x_set_config(struct tda998x_priv *priv,
(p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
if (p->audio_params.format != AFMT_UNUSED) {
- unsigned int ratio, route;
+ unsigned int route;
bool spdif = p->audio_params.format == AFMT_SPDIF;
route = AUDIO_ROUTE_I2S + spdif;
@@ -1771,8 +1798,8 @@ static int tda998x_set_config(struct tda998x_priv *priv,
priv->audio.ena_ap = p->audio_params.config;
priv->audio.i2s_format = I2S_FORMAT_PHILIPS;
- ratio = spdif ? 64 : p->audio_params.sample_width * 2;
- return tda998x_derive_cts_n(priv, &priv->audio, ratio);
+ return tda998x_derive_cts_n(priv, &priv->audio.cts_n,
+ p->audio_params.sample_width * 2);
}
return 0;