if (ctx->rt5682.is_legacy_cpu) { /* * The firmware might enable the clock at * boot (this information may or may not * be reflected in the enable clock register). * To change the rate we must disable the clock * first to cover these cases. Due to common * clock framework restrictions that do not allow * to disable a clock that has not been enabled, * we need to enable the clock first.
*/
ret = clk_prepare_enable(ctx->rt5682.mclk); if (!ret)
clk_disable_unprepare(ctx->rt5682.mclk);
ret = clk_set_rate(ctx->rt5682.mclk, 19200000);
if (ret)
dev_err(rtd->dev, "unable to set MCLK rate\n");
}
}
/* * Headset buttons map to the google Reference headset. * These can be configured by userspace.
*/
ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack",
SND_JACK_HEADSET | SND_JACK_BTN_0 |
SND_JACK_BTN_1 | SND_JACK_BTN_2 |
SND_JACK_BTN_3,
jack,
jack_pins,
ARRAY_SIZE(jack_pins)); if (ret) {
dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret;
}
if (ctx->rt5682.mclk_en) { if (ctx->rt5682.is_legacy_cpu) {
ret = clk_prepare_enable(ctx->rt5682.mclk); if (ret < 0) {
dev_err(rtd->dev, "could not configure MCLK state"); return ret;
}
}
switch (ctx->codec_type) { case CODEC_RT5650:
pll_source = RT5645_PLL1_S_MCLK; break; case CODEC_RT5682:
pll_source = RT5682_PLL1_S_MCLK; break; case CODEC_RT5682S:
pll_source = RT5682S_PLL_S_MCLK; break; default:
dev_err(rtd->dev, "invalid codec type %d\n",
ctx->codec_type); return -EINVAL;
}
/* get the tplg configured mclk. */
pll_in = sof_dai_get_mclk(rtd); if (pll_in <= 0) {
dev_err(rtd->dev, "invalid mclk freq %d\n", pll_in); return -EINVAL;
}
} else { switch (ctx->codec_type) { case CODEC_RT5650:
pll_source = RT5645_PLL1_S_BCLK1; break; case CODEC_RT5682:
pll_source = RT5682_PLL1_S_BCLK1; break; case CODEC_RT5682S:
pll_source = RT5682S_PLL_S_BCLK1; break; default:
dev_err(rtd->dev, "invalid codec type %d\n",
ctx->codec_type); return -EINVAL;
}
/* get the tplg configured bclk. */
pll_in = sof_dai_get_bclk(rtd); if (pll_in <= 0) {
dev_err(rtd->dev, "invalid bclk freq %d\n", pll_in); return -EINVAL;
}
}
pll_out = params_rate(params) * 512;
/* when MCLK is 512FS, no need to set PLL configuration additionally. */ if (pll_in == pll_out) { switch (ctx->codec_type) { case CODEC_RT5650:
clk_id = RT5645_SCLK_S_MCLK; break; case CODEC_RT5682:
clk_id = RT5682_SCLK_S_MCLK; break; case CODEC_RT5682S:
clk_id = RT5682S_SCLK_S_MCLK; break; default:
dev_err(rtd->dev, "invalid codec type %d\n",
ctx->codec_type); return -EINVAL;
}
} else { switch (ctx->codec_type) { case CODEC_RT5650:
pll_id = 0; /* not used in codec driver */
clk_id = RT5645_SCLK_S_PLL1; break; case CODEC_RT5682:
pll_id = RT5682_PLL1;
clk_id = RT5682_SCLK_S_PLL1; break; case CODEC_RT5682S: /* check plla_table and pllb_table in rt5682s.c */ switch (pll_in) { case 3072000: case 24576000: /* * For MCLK = 24.576MHz and sample rate = 96KHz case, use PLL1 We don't test * pll_out or params_rate() here since rt5682s PLL2 doesn't support 24.576MHz * input, so we have no choice but to use PLL1. Besides, we will not use PLL at * all if pll_in == pll_out. ex, MCLK = 24.576Mhz and sample rate = 48KHz
*/
pll_id = RT5682S_PLL1;
clk_id = RT5682S_SCLK_S_PLL1; break; default:
pll_id = RT5682S_PLL2;
clk_id = RT5682S_SCLK_S_PLL2; break;
} break; default:
dev_err(rtd->dev, "invalid codec type %d\n", ctx->codec_type); return -EINVAL;
}
/* Configure pll for codec */
ret = snd_soc_dai_set_pll(codec_dai, pll_id, pll_source, pll_in,
pll_out); if (ret < 0)
dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret);
}
/* Configure sysclk for codec */
ret = snd_soc_dai_set_sysclk(codec_dai, clk_id,
pll_out, SND_SOC_CLOCK_IN); if (ret < 0)
dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret);
/* * slot_width should equal or large than data length, set them * be the same
*/
ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2,
params_width(params)); if (ret < 0) {
dev_err(rtd->dev, "set TDM slot err:%d\n", ret); return ret;
}
staticconststruct snd_soc_dapm_route sof_map[] = { /* HP jack connectors - unknown if we have jack detection */
{ "Headphone Jack", NULL, "HPOL" },
{ "Headphone Jack", NULL, "HPOR" },
ret = snd_soc_dapm_new_controls(&card->dapm, rt5650_spk_widgets,
ARRAY_SIZE(rt5650_spk_widgets)); if (ret) {
dev_err(rtd->dev, "fail to add rt5650 spk widgets, ret %d\n",
ret); return ret;
}
ret = snd_soc_add_card_controls(card, rt5650_spk_kcontrols,
ARRAY_SIZE(rt5650_spk_kcontrols)); if (ret) {
dev_err(rtd->dev, "fail to add rt5650 spk kcontrols, ret %d\n",
ret); return ret;
}
ret = snd_soc_dapm_add_routes(&card->dapm, rt5650_spk_dapm_routes,
ARRAY_SIZE(rt5650_spk_dapm_routes)); if (ret)
dev_err(rtd->dev, "fail to add dapm routes, ret=%d\n", ret);
return ret;
}
/* sof audio machine driver for rt5682 codec */ staticstruct snd_soc_card sof_audio_card_rt5682 = {
.name = "rt5682", /* the sof- prefix is added by the core */
.owner = THIS_MODULE,
.controls = sof_controls,
.num_controls = ARRAY_SIZE(sof_controls),
.dapm_widgets = sof_widgets,
.num_dapm_widgets = ARRAY_SIZE(sof_widgets),
.dapm_routes = sof_map,
.num_dapm_routes = ARRAY_SIZE(sof_map),
.fully_routed = true,
.late_probe = sof_card_late_probe,
};
if (!ctx->rt5682.is_legacy_cpu) { /* * Currently, On SKL+ platforms MCLK will be turned off in sof * runtime suspended, and it will go into runtime suspended * right after playback is stop. However, rt5682 will output * static noise if sysclk turns off during playback. Set * ignore_pmdown_time to power down rt5682 immediately and * avoid the noise. * It can be removed once we can control MCLK by driver.
*/
ctx->codec_link->ignore_pmdown_time = 1;
}
if (ctx->amp_type == CODEC_NONE) return 0;
if (!ctx->amp_link) {
dev_err(dev, "amp link not available"); return -EINVAL;
}
/* codec-specific fields for speaker amplifier */ switch (ctx->amp_type) { case CODEC_MAX98357A:
max_98357a_dai_link(ctx->amp_link); break; case CODEC_MAX98360A:
max_98360a_dai_link(ctx->amp_link); break; case CODEC_MAX98373:
max_98373_dai_link(dev, ctx->amp_link); break; case CODEC_MAX98390:
max_98390_dai_link(dev, ctx->amp_link); break; case CODEC_RT1011:
sof_rt1011_dai_link(dev, ctx->amp_link); break; case CODEC_RT1015:
sof_rt1015_dai_link(ctx->amp_link); break; case CODEC_RT1015P:
sof_rt1015p_dai_link(ctx->amp_link); break; case CODEC_RT1019P:
sof_rt1019p_dai_link(ctx->amp_link); break; case CODEC_RT5650: /* use AIF2 to support speaker pipeline */
ctx->amp_link->codecs = &rt5650_components[1];
ctx->amp_link->num_codecs = 1;
ctx->amp_link->init = rt5650_spk_init;
ctx->amp_link->ops = &sof_rt5682_ops; break; default:
dev_err(dev, "invalid amp type %d\n", ctx->amp_type); return -EINVAL;
}
/* initialize ctx with board quirk */
ctx = sof_intel_board_get_ctx(&pdev->dev, sof_rt5682_quirk); if (!ctx) return -ENOMEM;
if (ctx->codec_type == CODEC_RT5650) {
card_name = devm_kstrdup(&pdev->dev, "rt5650", GFP_KERNEL); if (!card_name) return -ENOMEM;
sof_audio_card_rt5682.name = card_name;
/* create speaker dai link also */ if (ctx->amp_type == CODEC_NONE)
ctx->amp_type = CODEC_RT5650;
}
if (mach->mach_params.codec_mask & IDISP_CODEC_MASK)
ctx->hdmi.idisp_codec = true;
if (soc_intel_is_byt() || soc_intel_is_cht()) {
ctx->rt5682.is_legacy_cpu = true;
ctx->dmic_be_num = 0; /* HDMI is not supported by SOF on Baytrail/CherryTrail */
ctx->hdmi_num = 0;
} elseif (soc_intel_is_glk()) { /* dmic16k not support */
ctx->dmic_be_num = 1;
/* overwrite the DAI link order for GLK boards */
ctx->link_order_overwrite = GLK_LINK_ORDER;
/* backward-compatible with existing devices */ switch (ctx->amp_type) { case CODEC_MAX98357A:
card_name = devm_kstrdup(&pdev->dev, "glkrt5682max",
GFP_KERNEL); if (!card_name) return -ENOMEM;
if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) {
ctx->rt5682.mclk_en = true;
/* need to get main clock from pmc */ if (ctx->rt5682.is_legacy_cpu) {
ctx->rt5682.mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); if (IS_ERR(ctx->rt5682.mclk)) {
ret = PTR_ERR(ctx->rt5682.mclk);
dev_err(&pdev->dev, "Failed to get MCLK from pmc_plt_clk_3: %d\n",
ret); return ret;
}
ret = clk_prepare_enable(ctx->rt5682.mclk); if (ret < 0) {
dev_err(&pdev->dev, "could not configure MCLK state"); return ret;
}
}
}
/* update dai_link */
ret = sof_card_dai_links_create(&pdev->dev, &sof_audio_card_rt5682, ctx); if (ret) return ret;
/* update codec_conf */ switch (ctx->amp_type) { case CODEC_MAX98373:
max_98373_set_codec_conf(&sof_audio_card_rt5682); break; case CODEC_MAX98390:
max_98390_set_codec_conf(&pdev->dev, &sof_audio_card_rt5682); break; case CODEC_RT1011:
sof_rt1011_codec_conf(&pdev->dev, &sof_audio_card_rt5682); break; case CODEC_RT1015:
sof_rt1015_codec_conf(&sof_audio_card_rt5682); break; case CODEC_RT1015P:
sof_rt1015p_codec_conf(&sof_audio_card_rt5682); break; case CODEC_MAX98357A: case CODEC_MAX98360A: case CODEC_RT1019P: case CODEC_RT5650: case CODEC_NONE: /* no codec conf required */ break; default:
dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); return -EINVAL;
}
sof_audio_card_rt5682.dev = &pdev->dev;
/* set platform name for each dailink */
ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682,
mach->mach_params.platform); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.