drm/rockchip: dw-dp: enable audio through spdif and i2s switch

There are i2s and spdif interfaces for audio, default is i2s
When switching audio interfaces, both interfaces's mclk must be enabled
And can switch off after switching

Signed-off-by: Shunhua Lan <lsh@rock-chips.com>
Change-Id: I9007a2115c3c3fcdc5e68112aabcfab5fce5a5a8
This commit is contained in:
Shunhua Lan
2022-01-24 18:32:04 +08:00
committed by Tao Huang
parent dcdf88d54d
commit 9a06c19490

View File

@@ -221,8 +221,15 @@ struct dw_dp_video {
u8 bpp;
};
enum audio_format {
AFMT_I2S = 0,
AFMT_SPDIF = 1,
AFMT_UNUSED,
};
struct dw_dp_audio {
struct platform_device *pdev;
enum audio_format format;
u8 channels;
};
@@ -241,8 +248,11 @@ struct dw_dp {
struct device *dev;
struct regmap *regmap;
struct phy *phy;
struct clk_bulk_data *clks;
int nr_clks;
struct clk *apb_clk;
struct clk *aux_clk;
struct clk *hclk;
struct clk *i2s_clk;
struct clk *spdif_clk;
struct reset_control *rstc;
struct regmap *grf;
struct completion complete;
@@ -2343,15 +2353,20 @@ static int dw_dp_audio_hw_params(struct device *dev, void *data,
switch (daifmt->fmt) {
case HDMI_SPDIF:
audio_inf_select = 0x1;
audio->format = AFMT_SPDIF;
break;
case HDMI_I2S:
audio_inf_select = 0x0;
audio->format = AFMT_I2S;
break;
default:
dev_err(dp->dev, "invalid daifmt %d\n", daifmt->fmt);
return -EINVAL;
}
clk_prepare_enable(dp->spdif_clk);
clk_prepare_enable(dp->i2s_clk);
regmap_update_bits(dp->regmap, DPTX_AUD_CONFIG1,
AUDIO_DATA_IN_EN | NUM_CHANNELS | AUDIO_DATA_WIDTH |
AUDIO_INF_SELECT,
@@ -2360,6 +2375,13 @@ static int dw_dp_audio_hw_params(struct device *dev, void *data,
FIELD_PREP(AUDIO_DATA_WIDTH, params->sample_width) |
FIELD_PREP(AUDIO_INF_SELECT, audio_inf_select));
/* Wait for inf switch */
usleep_range(20, 40);
if (audio->format == AFMT_I2S)
clk_disable_unprepare(dp->spdif_clk);
else if (audio->format == AFMT_SPDIF)
clk_disable_unprepare(dp->i2s_clk);
return 0;
}
@@ -2427,9 +2449,17 @@ static int dw_dp_audio_startup(struct device *dev, void *data)
static void dw_dp_audio_shutdown(struct device *dev, void *data)
{
struct dw_dp *dp = dev_get_drvdata(dev);
struct dw_dp_audio *audio = &dp->audio;
regmap_update_bits(dp->regmap, DPTX_AUD_CONFIG1, AUDIO_DATA_IN_EN,
FIELD_PREP(AUDIO_DATA_IN_EN, 0));
if (audio->format == AFMT_SPDIF)
clk_disable_unprepare(dp->spdif_clk);
else if (audio->format == AFMT_I2S)
clk_disable_unprepare(dp->i2s_clk);
audio->format = AFMT_UNUSED;
}
static int dw_dp_audio_get_eld(struct device *dev, void *data, uint8_t *buf,
@@ -2460,6 +2490,7 @@ static int dw_dp_register_audio_driver(struct dw_dp *dp)
.max_i2s_channels = 8,
};
audio->format = AFMT_UNUSED;
audio->pdev = platform_device_register_data(dp->dev,
HDMI_CODEC_DRV_NAME,
PLATFORM_DEVID_AUTO,
@@ -2651,11 +2682,30 @@ static int dw_dp_probe(struct platform_device *pdev)
return dev_err_probe(dev, PTR_ERR(dp->phy),
"failed to get phy\n");
ret = devm_clk_bulk_get_all(dev, &dp->clks);
if (ret < 1)
return dev_err_probe(dev, ret, "failed to get clocks\n");
dp->apb_clk = devm_clk_get(dev, "apb");
if (IS_ERR(dp->apb_clk))
return dev_err_probe(dev, PTR_ERR(dp->apb_clk),
"failed to get apb clock\n");
dp->nr_clks = ret;
dp->aux_clk = devm_clk_get(dev, "aux");
if (IS_ERR(dp->aux_clk))
return dev_err_probe(dev, PTR_ERR(dp->aux_clk),
"failed to get aux clock\n");
dp->i2s_clk = devm_clk_get(dev, "i2s");
if (IS_ERR(dp->i2s_clk))
return dev_err_probe(dev, PTR_ERR(dp->i2s_clk),
"failed to get i2s clock\n");
dp->spdif_clk = devm_clk_get(dev, "spdif");
if (IS_ERR(dp->spdif_clk))
return dev_err_probe(dev, PTR_ERR(dp->spdif_clk),
"failed to get spdif clock\n");
dp->hclk = devm_clk_get_optional(dev, "hclk");
if (IS_ERR(dp->hclk))
return dev_err_probe(dev, PTR_ERR(dp->hclk),
"failed to get hclk\n");
dp->rstc = devm_reset_control_get(dev, NULL);
if (IS_ERR(dp->rstc))
@@ -2760,7 +2810,9 @@ static int __maybe_unused dw_dp_runtime_suspend(struct device *dev)
disable_irq(dp->irq);
clk_bulk_disable_unprepare(dp->nr_clks, dp->clks);
clk_disable_unprepare(dp->aux_clk);
clk_disable_unprepare(dp->apb_clk);
clk_disable_unprepare(dp->hclk);
return 0;
}
@@ -2768,11 +2820,10 @@ static int __maybe_unused dw_dp_runtime_suspend(struct device *dev)
static int __maybe_unused dw_dp_runtime_resume(struct device *dev)
{
struct dw_dp *dp = dev_get_drvdata(dev);
int ret;
ret = clk_bulk_prepare_enable(dp->nr_clks, dp->clks);
if (ret)
return ret;
clk_prepare_enable(dp->hclk);
clk_prepare_enable(dp->apb_clk);
clk_prepare_enable(dp->aux_clk);
reset_control_assert(dp->rstc);
udelay(10);