diff options
Diffstat (limited to '')
-rw-r--r-- | sound/soc/intel/boards/sof_da7219.c (renamed from sound/soc/intel/boards/sof_da7219_max98373.c) | 409 |
1 files changed, 248 insertions, 161 deletions
diff --git a/sound/soc/intel/boards/sof_da7219_max98373.c b/sound/soc/intel/boards/sof_da7219.c index bbd47e7e4..6eb5a6144 100644 --- a/sound/soc/intel/boards/sof_da7219_max98373.c +++ b/sound/soc/intel/boards/sof_da7219.c @@ -2,7 +2,7 @@ // Copyright(c) 2019 Intel Corporation. /* - * Intel SOF Machine driver for DA7219 + MAX98373/MAX98360A codec + * Intel SOF Machine driver for Dialog headphone codec */ #include <linux/input.h> @@ -13,24 +13,25 @@ #include <linux/platform_device.h> #include <sound/soc.h> #include <sound/soc-acpi.h> +#include <sound/sof.h> #include "../../codecs/da7219.h" #include "hda_dsp_common.h" +#include "sof_hdmi_common.h" +#include "sof_maxim_common.h" +#include "sof_ssp_common.h" -#define DIALOG_CODEC_DAI "da7219-hifi" -#define MAX98373_CODEC_DAI "max98373-aif1" -#define MAXIM_DEV0_NAME "i2c-MX98373:00" -#define MAXIM_DEV1_NAME "i2c-MX98373:01" +/* Board Quirks */ +#define SOF_DA7219_JSL_BOARD BIT(2) -struct hdmi_pcm { - struct list_head head; - struct snd_soc_dai *codec_dai; - int device; -}; +#define DIALOG_CODEC_DAI "da7219-hifi" struct card_private { - struct snd_soc_jack headset; - struct list_head hdmi_pcm_list; - struct snd_soc_jack hdmi[3]; + struct snd_soc_jack headset_jack; + struct sof_hdmi_private hdmi; + enum sof_ssp_codec codec_type; + enum sof_ssp_codec amp_type; + + unsigned int pll_bypass:1; }; static int platform_clock_control(struct snd_soc_dapm_widget *w, @@ -38,9 +39,14 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, { struct snd_soc_dapm_context *dapm = w->dapm; struct snd_soc_card *card = dapm->card; + struct card_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai *codec_dai; int ret = 0; + if (ctx->pll_bypass) + return ret; + + /* PLL SRM mode */ codec_dai = snd_soc_card_get_codec_dai(card, DIALOG_CODEC_DAI); if (!codec_dai) { dev_err(card->dev, "Codec dai not found; Unable to set/unset codec pll\n"); @@ -53,6 +59,8 @@ static int platform_clock_control(struct snd_soc_dapm_widget *w, if (ret) dev_err(card->dev, "failed to stop PLL: %d\n", ret); } else if (SND_SOC_DAPM_EVENT_ON(event)) { + dev_dbg(card->dev, "pll srm mode\n"); + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); if (ret) @@ -70,14 +78,6 @@ static const struct snd_kcontrol_new controls[] = { SOC_DAPM_PIN_SWITCH("Right Spk"), }; -static const struct snd_kcontrol_new m98360a_controls[] = { - SOC_DAPM_PIN_SWITCH("Headphone Jack"), - SOC_DAPM_PIN_SWITCH("Headset Mic"), - SOC_DAPM_PIN_SWITCH("Line Out"), - SOC_DAPM_PIN_SWITCH("Spk"), -}; - -/* For MAX98373 amp */ static const struct snd_soc_dapm_widget widgets[] = { SND_SOC_DAPM_HP("Headphone Jack", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), @@ -103,40 +103,6 @@ static const struct snd_soc_dapm_route audio_map[] = { { "Headset Mic", NULL, "Platform Clock" }, { "Line Out", NULL, "Platform Clock" }, - { "Left Spk", NULL, "Left BE_OUT" }, - { "Right Spk", NULL, "Right BE_OUT" }, - - /* digital mics */ - {"DMic", NULL, "SoC DMIC"}, -}; - -/* For MAX98360A amp */ -static const struct snd_soc_dapm_widget max98360a_widgets[] = { - SND_SOC_DAPM_HP("Headphone Jack", NULL), - SND_SOC_DAPM_MIC("Headset Mic", NULL), - SND_SOC_DAPM_LINE("Line Out", NULL), - - SND_SOC_DAPM_SPK("Spk", NULL), - - SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, - platform_clock_control, SND_SOC_DAPM_POST_PMD | - SND_SOC_DAPM_PRE_PMU), - - SND_SOC_DAPM_MIC("SoC DMIC", NULL), -}; - -static const struct snd_soc_dapm_route max98360a_map[] = { - { "Headphone Jack", NULL, "HPL" }, - { "Headphone Jack", NULL, "HPR" }, - - { "MIC", NULL, "Headset Mic" }, - - { "Headphone Jack", NULL, "Platform Clock" }, - { "Headset Mic", NULL, "Platform Clock" }, - { "Line Out", NULL, "Platform Clock" }, - - {"Spk", NULL, "Speaker"}, - /* digital mics */ {"DMic", NULL, "SoC DMIC"}, }; @@ -156,24 +122,45 @@ static struct snd_soc_jack_pin jack_pins[] = { }, }; -static struct snd_soc_jack headset; - static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); + struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = codec_dai->component; - struct snd_soc_jack *jack; - int ret; + struct snd_soc_jack *jack = &ctx->headset_jack; + int mclk_rate, ret; + + mclk_rate = sof_dai_get_mclk(rtd); + if (mclk_rate <= 0) { + dev_err(rtd->dev, "invalid mclk freq %d\n", mclk_rate); + return -EINVAL; + } - /* Configure sysclk for codec */ - ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, 24000000, + ret = snd_soc_dai_set_sysclk(codec_dai, DA7219_CLKSRC_MCLK, mclk_rate, SND_SOC_CLOCK_IN); if (ret) { - dev_err(rtd->dev, "can't set codec sysclk configuration\n"); + dev_err(rtd->dev, "fail to set sysclk, ret %d\n", ret); return ret; } /* + * Use PLL bypass mode if MCLK is available, be sure to set the + * frequency of MCLK to 12.288 or 24.576MHz on topology side. + */ + if (mclk_rate == 12288000 || mclk_rate == 24576000) { + /* PLL bypass mode */ + dev_dbg(rtd->dev, "pll bypass mode, mclk rate %d\n", mclk_rate); + + ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0); + if (ret) { + dev_err(rtd->dev, "fail to set pll, ret %d\n", ret); + return ret; + } + + ctx->pll_bypass = 1; + } + + /* * Headset buttons map to the google Reference headset. * These can be configured by userspace. */ @@ -181,34 +168,36 @@ static int da7219_codec_init(struct snd_soc_pcm_runtime *rtd) SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3 | SND_JACK_LINEOUT, - &headset, - jack_pins, - ARRAY_SIZE(jack_pins)); + jack, jack_pins, ARRAY_SIZE(jack_pins)); if (ret) { dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); return ret; } - jack = &headset; snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); - snd_soc_component_set_jack(component, jack, NULL); + + ret = snd_soc_component_set_jack(component, jack, NULL); + if (ret) { + dev_err(rtd->dev, "fail to set component jack, ret %d\n", ret); + return ret; + } return ret; } -static int ssp1_hw_params(struct snd_pcm_substream *substream, +static int max98373_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct snd_soc_pcm_runtime *runtime = asoc_substream_to_rtd(substream); + struct snd_soc_pcm_runtime *runtime = snd_soc_substream_to_rtd(substream); int ret, j; for (j = 0; j < runtime->dai_link->num_codecs; j++) { - struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(runtime, j); + struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(runtime, j); - if (!strcmp(codec_dai->component->name, MAXIM_DEV0_NAME)) { + if (!strcmp(codec_dai->component->name, MAX_98373_DEV0_NAME)) { /* vmon_slot_no = 0 imon_slot_no = 1 for TX slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x3, 3, 4, 16); if (ret < 0) { @@ -216,7 +205,7 @@ static int ssp1_hw_params(struct snd_pcm_substream *substream, return ret; } } - if (!strcmp(codec_dai->component->name, MAXIM_DEV1_NAME)) { + if (!strcmp(codec_dai->component->name, MAX_98373_DEV1_NAME)) { /* vmon_slot_no = 2 imon_slot_no = 3 for TX slots */ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xC, 3, 4, 16); if (ret < 0) { @@ -229,35 +218,16 @@ static int ssp1_hw_params(struct snd_pcm_substream *substream, return 0; } -static struct snd_soc_ops ssp1_ops = { - .hw_params = ssp1_hw_params, -}; - -static struct snd_soc_codec_conf max98373_codec_conf[] = { - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV0_NAME), - .name_prefix = "Right", - }, - { - .dlc = COMP_CODEC_CONF(MAXIM_DEV1_NAME), - .name_prefix = "Left", - }, +static const struct snd_soc_ops max98373_ops = { + .hw_params = max98373_hw_params, }; static int hdmi_init(struct snd_soc_pcm_runtime *rtd) { struct card_private *ctx = snd_soc_card_get_drvdata(rtd->card); - struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); - struct hdmi_pcm *pcm; - - pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); - if (!pcm) - return -ENOMEM; + struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); - pcm->device = dai->id; - pcm->codec_dai = dai; - - list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); + ctx->hdmi.hdmi_comp = dai->component; return 0; } @@ -265,17 +235,14 @@ static int hdmi_init(struct snd_soc_pcm_runtime *rtd) static int card_late_probe(struct snd_soc_card *card) { struct card_private *ctx = snd_soc_card_get_drvdata(card); - struct snd_soc_acpi_mach *mach = (card->dev)->platform_data; - struct hdmi_pcm *pcm; - - if (mach->mach_params.common_hdmi_codec_drv) { - pcm = list_first_entry(&ctx->hdmi_pcm_list, struct hdmi_pcm, - head); - return hda_dsp_hdmi_build_controls(card, - pcm->codec_dai->component); - } - return -EINVAL; + if (!ctx->hdmi.idisp_codec) + return 0; + + if (!ctx->hdmi.hdmi_comp) + return -EINVAL; + + return hda_dsp_hdmi_build_controls(card, ctx->hdmi.hdmi_comp); } SND_SOC_DAILINK_DEF(ssp0_pin, @@ -285,13 +252,11 @@ SND_SOC_DAILINK_DEF(ssp0_codec, SND_SOC_DAILINK_DEF(ssp1_pin, DAILINK_COMP_ARRAY(COMP_CPU("SSP1 Pin"))); -SND_SOC_DAILINK_DEF(ssp1_amps, - DAILINK_COMP_ARRAY( - /* Left */ COMP_CODEC(MAXIM_DEV0_NAME, MAX98373_CODEC_DAI), - /* Right */ COMP_CODEC(MAXIM_DEV1_NAME, MAX98373_CODEC_DAI))); -SND_SOC_DAILINK_DEF(ssp1_m98360a, - DAILINK_COMP_ARRAY(COMP_CODEC("MX98360A:00", "HiFi"))); +SND_SOC_DAILINK_DEF(ssp2_pin, + DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); +SND_SOC_DAILINK_DEF(dummy_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai"))); SND_SOC_DAILINK_DEF(dmic_pin, DAILINK_COMP_ARRAY(COMP_CPU("DMIC01 Pin"))); @@ -316,10 +281,15 @@ SND_SOC_DAILINK_DEF(idisp3_pin, SND_SOC_DAILINK_DEF(idisp3_codec, DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi3"))); +SND_SOC_DAILINK_DEF(idisp4_pin, + DAILINK_COMP_ARRAY(COMP_CPU("iDisp4 Pin"))); +SND_SOC_DAILINK_DEF(idisp4_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("ehdaudio0D2", "intel-hdmi-hifi4"))); + SND_SOC_DAILINK_DEF(platform, /* subject to be overridden during probe */ DAILINK_COMP_ARRAY(COMP_PLATFORM("0000:00:1f.3"))); -static struct snd_soc_dai_link dais[] = { +static struct snd_soc_dai_link jsl_dais[] = { /* Back End DAI links */ { .name = "SSP1-Codec", @@ -328,8 +298,7 @@ static struct snd_soc_dai_link dais[] = { .no_pcm = 1, .dpcm_playback = 1, .dpcm_capture = 1, /* IV feedback */ - .ops = &ssp1_ops, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_amps, platform), + SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform), }, { .name = "SSP0-Codec", @@ -383,83 +352,198 @@ static struct snd_soc_dai_link dais[] = { } }; -static struct snd_soc_card card_da7219_m98373 = { - .name = "da7219max", +static struct snd_soc_dai_link adl_dais[] = { + /* Back End DAI links */ + { + .name = "SSP0-Codec", + .id = 0, + .no_pcm = 1, + .init = da7219_codec_init, + .ignore_pmdown_time = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(ssp0_pin, ssp0_codec, platform), + }, + { + .name = "dmic01", + .id = 1, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic_pin, dmic_codec, platform), + }, + { + .name = "dmic16k", + .id = 2, + .ignore_suspend = 1, + .dpcm_capture = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(dmic16k_pin, dmic_codec, platform), + }, + { + .name = "iDisp1", + .id = 3, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp1_pin, idisp1_codec, platform), + }, + { + .name = "iDisp2", + .id = 4, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp2_pin, idisp2_codec, platform), + }, + { + .name = "iDisp3", + .id = 5, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp3_pin, idisp3_codec, platform), + }, + { + .name = "iDisp4", + .id = 6, + .init = hdmi_init, + .dpcm_playback = 1, + .no_pcm = 1, + SND_SOC_DAILINK_REG(idisp4_pin, idisp4_codec, platform), + }, + { + .name = "SSP1-Codec", + .id = 7, + .no_pcm = 1, + .dpcm_playback = 1, + /* feedback stream or firmware-generated echo reference */ + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(ssp1_pin, max_98373_components, platform), + }, + { + .name = "SSP2-BT", + .id = 8, + .no_pcm = 1, + .dpcm_playback = 1, + .dpcm_capture = 1, + SND_SOC_DAILINK_REG(ssp2_pin, dummy_codec, platform), + }, +}; + +static struct snd_soc_card card_da7219 = { + .name = "da7219", /* the sof- prefix is added by the core */ .owner = THIS_MODULE, - .dai_link = dais, - .num_links = ARRAY_SIZE(dais), .controls = controls, .num_controls = ARRAY_SIZE(controls), .dapm_widgets = widgets, .num_dapm_widgets = ARRAY_SIZE(widgets), .dapm_routes = audio_map, .num_dapm_routes = ARRAY_SIZE(audio_map), - .codec_conf = max98373_codec_conf, - .num_configs = ARRAY_SIZE(max98373_codec_conf), - .fully_routed = true, - .late_probe = card_late_probe, -}; - -static struct snd_soc_card card_da7219_m98360a = { - .name = "da7219max98360a", - .owner = THIS_MODULE, - .dai_link = dais, - .num_links = ARRAY_SIZE(dais), - .controls = m98360a_controls, - .num_controls = ARRAY_SIZE(m98360a_controls), - .dapm_widgets = max98360a_widgets, - .num_dapm_widgets = ARRAY_SIZE(max98360a_widgets), - .dapm_routes = max98360a_map, - .num_dapm_routes = ARRAY_SIZE(max98360a_map), .fully_routed = true, .late_probe = card_late_probe, }; static int audio_probe(struct platform_device *pdev) { - static struct snd_soc_card *card; - struct snd_soc_acpi_mach *mach; + struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; + struct snd_soc_dai_link *dai_links; struct card_private *ctx; - int ret; + unsigned long board_quirk = 0; + int ret, amp_idx; ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; - /* By default dais[0] is configured for max98373 */ - if (!strcmp(pdev->name, "sof_da7219_mx98360a")) { - dais[0] = (struct snd_soc_dai_link) { - .name = "SSP1-Codec", - .id = 0, - .no_pcm = 1, - .dpcm_playback = 1, - .ignore_pmdown_time = 1, - SND_SOC_DAILINK_REG(ssp1_pin, ssp1_m98360a, platform) }; + if (pdev->id_entry && pdev->id_entry->driver_data) + board_quirk = (unsigned long)pdev->id_entry->driver_data; + + ctx->codec_type = sof_ssp_detect_codec_type(&pdev->dev); + ctx->amp_type = sof_ssp_detect_amp_type(&pdev->dev); + + if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) + ctx->hdmi.idisp_codec = true; + + if (board_quirk & SOF_DA7219_JSL_BOARD) { + /* backward-compatible with existing devices */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + card_da7219.name = devm_kstrdup(&pdev->dev, + "da7219max98360a", + GFP_KERNEL); + break; + case CODEC_MAX98373: + card_da7219.name = devm_kstrdup(&pdev->dev, "da7219max", + GFP_KERNEL); + break; + default: + break; + } + + dai_links = jsl_dais; + amp_idx = 0; + + card_da7219.num_links = ARRAY_SIZE(jsl_dais); + } else { + dai_links = adl_dais; + amp_idx = 7; + + card_da7219.num_links = ARRAY_SIZE(adl_dais); } - INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - card = (struct snd_soc_card *)pdev->id_entry->driver_data; - card->dev = &pdev->dev; + dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); + + /* speaker amp */ + switch (ctx->amp_type) { + case CODEC_MAX98360A: + max_98360a_dai_link(&dai_links[amp_idx]); + break; + case CODEC_MAX98373: + dai_links[amp_idx].codecs = max_98373_components; + dai_links[amp_idx].num_codecs = ARRAY_SIZE(max_98373_components); + dai_links[amp_idx].init = max_98373_spk_codec_init; + if (board_quirk & SOF_DA7219_JSL_BOARD) { + dai_links[amp_idx].ops = &max98373_ops; /* use local ops */ + } else { + /* TBD: implement the amp for later platform */ + dev_err(&pdev->dev, "max98373 not support yet\n"); + return -EINVAL; + } + + max_98373_set_codec_conf(&card_da7219); + break; + default: + dev_err(&pdev->dev, "invalid amp type %d\n", ctx->amp_type); + return -EINVAL; + } - mach = pdev->dev.platform_data; - ret = snd_soc_fixup_dai_links_platform_name(card, + card_da7219.dai_link = dai_links; + + card_da7219.dev = &pdev->dev; + + ret = snd_soc_fixup_dai_links_platform_name(&card_da7219, mach->mach_params.platform); if (ret) return ret; - snd_soc_card_set_drvdata(card, ctx); + snd_soc_card_set_drvdata(&card_da7219, ctx); - return devm_snd_soc_register_card(&pdev->dev, card); + return devm_snd_soc_register_card(&pdev->dev, &card_da7219); } static const struct platform_device_id board_ids[] = { { - .name = "sof_da7219_mx98373", - .driver_data = (kernel_ulong_t)&card_da7219_m98373, + .name = "jsl_mx98373_da7219", + .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD), + }, + { + .name = "jsl_mx98360_da7219", + .driver_data = (kernel_ulong_t)(SOF_DA7219_JSL_BOARD), }, { - .name = "sof_da7219_mx98360a", - .driver_data = (kernel_ulong_t)&card_da7219_m98360a, + .name = "adl_mx98360_da7219", + /* no quirk needed for this board */ }, { } }; @@ -468,7 +552,7 @@ MODULE_DEVICE_TABLE(platform, board_ids); static struct platform_driver audio = { .probe = audio_probe, .driver = { - .name = "sof_da7219_max98_360a_373", + .name = "sof_da7219", .pm = &snd_soc_pm_ops, }, .id_table = board_ids, @@ -476,7 +560,10 @@ static struct platform_driver audio = { module_platform_driver(audio) /* Module information */ -MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver"); +MODULE_DESCRIPTION("ASoC Intel(R) SOF Machine driver for Dialog codec"); MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); +MODULE_AUTHOR("Brent Lu <brent.lu@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_MAXIM_COMMON); +MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_SSP_COMMON); |