diff options
Diffstat (limited to 'sound/soc/intel/boards/sof_rt5682.c')
-rw-r--r-- | sound/soc/intel/boards/sof_rt5682.c | 165 |
1 files changed, 118 insertions, 47 deletions
diff --git a/sound/soc/intel/boards/sof_rt5682.c b/sound/soc/intel/boards/sof_rt5682.c index 3343dbcd506f..daeaa396d928 100644 --- a/sound/soc/intel/boards/sof_rt5682.c +++ b/sound/soc/intel/boards/sof_rt5682.c @@ -9,9 +9,8 @@ #include <linux/input.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/clk.h> #include <linux/dmi.h> -#include <asm/cpu_device_id.h> -#include <asm/intel-family.h> #include <sound/core.h> #include <sound/jack.h> #include <sound/pcm.h> @@ -21,6 +20,7 @@ #include <sound/soc-acpi.h> #include "../../codecs/rt5682.h" #include "../../codecs/hdac_hdmi.h" +#include "../common/soc-intel-quirks.h" #define NAME_SIZE 32 @@ -33,6 +33,7 @@ #define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) #define SOF_RT5682_SSP_AMP(quirk) \ (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) +#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) /* Default: MCLK on, MCLK 19.2M, SSP0 */ static unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | @@ -49,6 +50,7 @@ struct sof_hdmi_pcm { }; struct sof_card_private { + struct clk *mclk; struct snd_soc_jack sof_headset; struct list_head hdmi_pcm_list; }; @@ -63,6 +65,22 @@ static const struct dmi_system_id sof_rt5682_quirk_table[] = { { .callback = sof_rt5682_quirk_cb, .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), + DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"), + }, + .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), + DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"), + }, + .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), + }, + { + .callback = sof_rt5682_quirk_cb, + .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), }, @@ -128,6 +146,27 @@ static int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) RT5682_CLK_SEL_I2S1_ASRC); } + if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + /* + * 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->mclk); + if (!ret) + clk_disable_unprepare(ctx->mclk); + + ret = clk_set_rate(ctx->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. @@ -162,10 +201,20 @@ static int sof_rt5682_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); struct snd_soc_dai *codec_dai = rtd->codec_dai; int clk_id, clk_freq, pll_out, ret; if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { + if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(rtd->dev, + "could not configure MCLK state"); + return ret; + } + } + clk_id = RT5682_PLL1_S_MCLK; if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) clk_freq = 24000000; @@ -304,12 +353,6 @@ static struct snd_soc_card sof_audio_card_rt5682 = { .late_probe = sof_card_late_probe, }; -static const struct x86_cpu_id legacy_cpi_ids[] = { - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Baytrail */ - { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT }, /* Cherrytrail */ - {} -}; - static struct snd_soc_dai_link_component rt5682_component[] = { { .name = "i2c-10EC5682:00", @@ -334,16 +377,19 @@ static struct snd_soc_dai_link_component max98357a_component[] = { static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, int ssp_codec, int ssp_amp, - int dmic_num, + int dmic_be_num, int hdmi_num) { struct snd_soc_dai_link_component *idisp_components; + struct snd_soc_dai_link_component *cpus; struct snd_soc_dai_link *links; int i, id = 0; links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * sof_audio_card_rt5682.num_links, GFP_KERNEL); - if (!links) + cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * + sof_audio_card_rt5682.num_links, GFP_KERNEL); + if (!links || !cpus) goto devm_err; /* codec SSP */ @@ -363,11 +409,13 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].dpcm_playback = 1; links[id].dpcm_capture = 1; links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; if (is_legacy_cpu) { - links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_codec); - if (!links[id].cpu_dai_name) + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "ssp%d-port", + ssp_codec); + if (!links[id].cpus->dai_name) goto devm_err; } else { /* @@ -380,27 +428,32 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, * It can be removed once we can control MCLK by driver. */ links[id].ignore_pmdown_time = 1; - links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_codec); - if (!links[id].cpu_dai_name) + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_codec); + if (!links[id].cpus->dai_name) goto devm_err; } id++; /* dmic */ - for (i = 1; i <= dmic_num; i++) { - links[id].name = devm_kasprintf(dev, GFP_KERNEL, - "dmic%02d", i); - if (!links[id].name) - goto devm_err; + if (dmic_be_num > 0) { + /* at least we have dmic01 */ + links[id].name = "dmic01"; + links[id].cpus = &cpus[id]; + links[id].cpus->dai_name = "DMIC01 Pin"; + if (dmic_be_num > 1) { + /* set up 2 BE links at most */ + links[id + 1].name = "dmic16k"; + links[id + 1].cpus = &cpus[id + 1]; + links[id + 1].cpus->dai_name = "DMIC16k Pin"; + dmic_be_num = 2; + } + } + for (i = 0; i < dmic_be_num; i++) { links[id].id = id; - links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "DMIC%02d Pin", i); - if (!links[id].cpu_dai_name) - goto devm_err; - + links[id].num_cpus = 1; links[id].codecs = dmic_component; links[id].num_codecs = ARRAY_SIZE(dmic_component); links[id].platforms = platform_component; @@ -426,9 +479,11 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, goto devm_err; links[id].id = id; - links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "iDisp%d Pin", i); - if (!links[id].cpu_dai_name) + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "iDisp%d Pin", i); + if (!links[id].cpus->dai_name) goto devm_err; idisp_components[i - 1].name = "ehdaudio0D2"; @@ -465,18 +520,20 @@ static struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, links[id].nonatomic = true; links[id].dpcm_playback = 1; links[id].no_pcm = 1; + links[id].cpus = &cpus[id]; + links[id].num_cpus = 1; if (is_legacy_cpu) { - links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "ssp%d-port", - ssp_amp); - if (!links[id].cpu_dai_name) + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "ssp%d-port", + ssp_amp); + if (!links[id].cpus->dai_name) goto devm_err; } else { - links[id].cpu_dai_name = devm_kasprintf(dev, GFP_KERNEL, - "SSP%d Pin", - ssp_amp); - if (!links[id].cpu_dai_name) + links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, + "SSP%d Pin", + ssp_amp); + if (!links[id].cpus->dai_name) goto devm_err; } } @@ -491,26 +548,39 @@ static int sof_audio_probe(struct platform_device *pdev) struct snd_soc_dai_link *dai_links; struct snd_soc_acpi_mach *mach; struct sof_card_private *ctx; - int dmic_num, hdmi_num; + int dmic_be_num, hdmi_num; int ret, ssp_amp, ssp_codec; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); + ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; - if (x86_match_cpu(legacy_cpi_ids)) { + if (soc_intel_is_byt() || soc_intel_is_cht()) { is_legacy_cpu = 1; - dmic_num = 0; + dmic_be_num = 0; hdmi_num = 0; /* default quirk for legacy cpu */ - sof_rt5682_quirk = SOF_RT5682_SSP_CODEC(2); + sof_rt5682_quirk = SOF_RT5682_MCLK_EN | + SOF_RT5682_MCLK_BYTCHT_EN | + SOF_RT5682_SSP_CODEC(2); } else { - dmic_num = 1; + dmic_be_num = 2; hdmi_num = 3; } dmi_check_system(sof_rt5682_quirk_table); + /* need to get main clock from pmc */ + if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { + ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); + ret = clk_prepare_enable(ctx->mclk); + if (ret < 0) { + dev_err(&pdev->dev, + "could not configure MCLK state"); + return ret; + } + } + dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> @@ -519,12 +589,13 @@ static int sof_audio_probe(struct platform_device *pdev) ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; /* compute number of dai links */ - sof_audio_card_rt5682.num_links = 1 + dmic_num + hdmi_num; + sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num; + if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) sof_audio_card_rt5682.num_links++; dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, - dmic_num, hdmi_num); + dmic_be_num, hdmi_num); if (!dai_links) return -ENOMEM; |