mirror of https://gitee.com/openkylin/linux.git
drm/i2c: tda998x: implement different I2S flavours
Add support for the left and right justified I2S formats as well as the more tranditional "Philips" I2S format. Tested-by: Peter Ujfalusi <peter.ujfalusi@ti.com> Tested-by: Sven Van Asbroeck <TheSven73@gmail.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
parent
2e9943aab5
commit
935b9ca357
|
@ -42,6 +42,7 @@ struct tda998x_audio_port {
|
||||||
|
|
||||||
struct tda998x_audio_settings {
|
struct tda998x_audio_settings {
|
||||||
struct tda998x_audio_params params;
|
struct tda998x_audio_params params;
|
||||||
|
u8 i2s_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tda998x_priv {
|
struct tda998x_priv {
|
||||||
|
@ -246,7 +247,9 @@ struct tda998x_priv {
|
||||||
# define HVF_CNTRL_1_SEMI_PLANAR (1 << 6)
|
# define HVF_CNTRL_1_SEMI_PLANAR (1 << 6)
|
||||||
#define REG_RPT_CNTRL REG(0x00, 0xf0) /* write */
|
#define REG_RPT_CNTRL REG(0x00, 0xf0) /* write */
|
||||||
#define REG_I2S_FORMAT REG(0x00, 0xfc) /* read/write */
|
#define REG_I2S_FORMAT REG(0x00, 0xfc) /* read/write */
|
||||||
# define I2S_FORMAT(x) (((x) & 3) << 0)
|
# define I2S_FORMAT_PHILIPS (0 << 0)
|
||||||
|
# define I2S_FORMAT_LEFT_J (2 << 0)
|
||||||
|
# define I2S_FORMAT_RIGHT_J (3 << 0)
|
||||||
#define REG_AIP_CLKSEL REG(0x00, 0xfd) /* write */
|
#define REG_AIP_CLKSEL REG(0x00, 0xfd) /* write */
|
||||||
# define AIP_CLKSEL_AIP_SPDIF (0 << 3)
|
# define AIP_CLKSEL_AIP_SPDIF (0 << 3)
|
||||||
# define AIP_CLKSEL_AIP_I2S (1 << 3)
|
# define AIP_CLKSEL_AIP_I2S (1 << 3)
|
||||||
|
@ -918,6 +921,7 @@ static int tda998x_configure_audio(struct tda998x_priv *priv,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reg_write(priv, REG_I2S_FORMAT, settings->i2s_format);
|
||||||
reg_write(priv, REG_AIP_CLKSEL, clksel_aip);
|
reg_write(priv, REG_AIP_CLKSEL, clksel_aip);
|
||||||
reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT |
|
reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT |
|
||||||
AIP_CNTRL_0_ACR_MAN); /* auto CTS */
|
AIP_CNTRL_0_ACR_MAN); /* auto CTS */
|
||||||
|
@ -984,6 +988,7 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
|
||||||
struct hdmi_codec_params *params)
|
struct hdmi_codec_params *params)
|
||||||
{
|
{
|
||||||
struct tda998x_priv *priv = dev_get_drvdata(dev);
|
struct tda998x_priv *priv = dev_get_drvdata(dev);
|
||||||
|
bool spdif = daifmt->fmt == HDMI_SPDIF;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
struct tda998x_audio_settings audio = {
|
struct tda998x_audio_settings audio = {
|
||||||
.params = {
|
.params = {
|
||||||
|
@ -998,35 +1003,43 @@ static int tda998x_audio_hw_params(struct device *dev, void *data,
|
||||||
|
|
||||||
switch (daifmt->fmt) {
|
switch (daifmt->fmt) {
|
||||||
case HDMI_I2S:
|
case HDMI_I2S:
|
||||||
if (daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
|
audio.i2s_format = I2S_FORMAT_PHILIPS;
|
||||||
daifmt->bit_clk_master || daifmt->frame_clk_master) {
|
break;
|
||||||
dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
|
case HDMI_LEFT_J:
|
||||||
daifmt->bit_clk_inv, daifmt->frame_clk_inv,
|
audio.i2s_format = I2S_FORMAT_LEFT_J;
|
||||||
daifmt->bit_clk_master,
|
break;
|
||||||
daifmt->frame_clk_master);
|
case HDMI_RIGHT_J:
|
||||||
return -EINVAL;
|
audio.i2s_format = I2S_FORMAT_RIGHT_J;
|
||||||
}
|
|
||||||
for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
|
|
||||||
if (priv->audio_port[i].format == AFMT_I2S)
|
|
||||||
audio.params.config = priv->audio_port[i].config;
|
|
||||||
audio.params.format = AFMT_I2S;
|
|
||||||
break;
|
break;
|
||||||
case HDMI_SPDIF:
|
case HDMI_SPDIF:
|
||||||
for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
|
audio.i2s_format = 0;
|
||||||
if (priv->audio_port[i].format == AFMT_SPDIF)
|
|
||||||
audio.params.config = priv->audio_port[i].config;
|
|
||||||
audio.params.format = AFMT_SPDIF;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
|
dev_err(dev, "%s: Invalid format %d\n", __func__, daifmt->fmt);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
audio.params.format = spdif ? AFMT_SPDIF : AFMT_I2S;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(priv->audio_port); i++)
|
||||||
|
if (priv->audio_port[i].format == audio.params.format)
|
||||||
|
audio.params.config = priv->audio_port[i].config;
|
||||||
|
|
||||||
if (audio.params.config == 0) {
|
if (audio.params.config == 0) {
|
||||||
dev_err(dev, "%s: No audio configuration found\n", __func__);
|
dev_err(dev, "%s: No audio configuration found\n", __func__);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!spdif &&
|
||||||
|
(daifmt->bit_clk_inv || daifmt->frame_clk_inv ||
|
||||||
|
daifmt->bit_clk_master || daifmt->frame_clk_master)) {
|
||||||
|
dev_err(dev, "%s: Bad flags %d %d %d %d\n", __func__,
|
||||||
|
daifmt->bit_clk_inv, daifmt->frame_clk_inv,
|
||||||
|
daifmt->bit_clk_master,
|
||||||
|
daifmt->frame_clk_master);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&priv->audio_mutex);
|
mutex_lock(&priv->audio_mutex);
|
||||||
if (priv->supports_infoframes && priv->sink_has_audio)
|
if (priv->supports_infoframes && priv->sink_has_audio)
|
||||||
ret = tda998x_configure_audio(priv, &audio);
|
ret = tda998x_configure_audio(priv, &audio);
|
||||||
|
@ -1631,8 +1644,10 @@ static void tda998x_set_config(struct tda998x_priv *priv,
|
||||||
VIP_CNTRL_2_SWAP_F(p->swap_f) |
|
VIP_CNTRL_2_SWAP_F(p->swap_f) |
|
||||||
(p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
|
(p->mirr_f ? VIP_CNTRL_2_MIRR_F : 0);
|
||||||
|
|
||||||
if (p->audio_params.format != AFMT_UNUSED)
|
if (p->audio_params.format != AFMT_UNUSED) {
|
||||||
priv->audio.params = p->audio_params;
|
priv->audio.params = p->audio_params;
|
||||||
|
priv->audio.i2s_format = I2S_FORMAT_PHILIPS;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tda998x_destroy(struct device *dev)
|
static void tda998x_destroy(struct device *dev)
|
||||||
|
|
Loading…
Reference in New Issue