18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci// Copyright(c) 2019-2020 Intel Corporation. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* 58c2ecf20Sopenharmony_ci * Intel SOF Machine Driver with Realtek rt5682 Codec 68c2ecf20Sopenharmony_ci * and speaker codec MAX98357A or RT1015. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/i2c.h> 98c2ecf20Sopenharmony_ci#include <linux/input.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/clk.h> 138c2ecf20Sopenharmony_ci#include <linux/dmi.h> 148c2ecf20Sopenharmony_ci#include <sound/core.h> 158c2ecf20Sopenharmony_ci#include <sound/jack.h> 168c2ecf20Sopenharmony_ci#include <sound/pcm.h> 178c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 188c2ecf20Sopenharmony_ci#include <sound/soc.h> 198c2ecf20Sopenharmony_ci#include <sound/rt5682.h> 208c2ecf20Sopenharmony_ci#include <sound/soc-acpi.h> 218c2ecf20Sopenharmony_ci#include "../../codecs/rt1015.h" 228c2ecf20Sopenharmony_ci#include "../../codecs/rt5682.h" 238c2ecf20Sopenharmony_ci#include "../../codecs/hdac_hdmi.h" 248c2ecf20Sopenharmony_ci#include "../common/soc-intel-quirks.h" 258c2ecf20Sopenharmony_ci#include "hda_dsp_common.h" 268c2ecf20Sopenharmony_ci#include "sof_maxim_common.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define NAME_SIZE 32 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define SOF_RT5682_SSP_CODEC(quirk) ((quirk) & GENMASK(2, 0)) 318c2ecf20Sopenharmony_ci#define SOF_RT5682_SSP_CODEC_MASK (GENMASK(2, 0)) 328c2ecf20Sopenharmony_ci#define SOF_RT5682_MCLK_EN BIT(3) 338c2ecf20Sopenharmony_ci#define SOF_RT5682_MCLK_24MHZ BIT(4) 348c2ecf20Sopenharmony_ci#define SOF_SPEAKER_AMP_PRESENT BIT(5) 358c2ecf20Sopenharmony_ci#define SOF_RT5682_SSP_AMP_SHIFT 6 368c2ecf20Sopenharmony_ci#define SOF_RT5682_SSP_AMP_MASK (GENMASK(8, 6)) 378c2ecf20Sopenharmony_ci#define SOF_RT5682_SSP_AMP(quirk) \ 388c2ecf20Sopenharmony_ci (((quirk) << SOF_RT5682_SSP_AMP_SHIFT) & SOF_RT5682_SSP_AMP_MASK) 398c2ecf20Sopenharmony_ci#define SOF_RT5682_MCLK_BYTCHT_EN BIT(9) 408c2ecf20Sopenharmony_ci#define SOF_RT5682_NUM_HDMIDEV_SHIFT 10 418c2ecf20Sopenharmony_ci#define SOF_RT5682_NUM_HDMIDEV_MASK (GENMASK(12, 10)) 428c2ecf20Sopenharmony_ci#define SOF_RT5682_NUM_HDMIDEV(quirk) \ 438c2ecf20Sopenharmony_ci ((quirk << SOF_RT5682_NUM_HDMIDEV_SHIFT) & SOF_RT5682_NUM_HDMIDEV_MASK) 448c2ecf20Sopenharmony_ci#define SOF_RT1015_SPEAKER_AMP_PRESENT BIT(13) 458c2ecf20Sopenharmony_ci#define SOF_MAX98373_SPEAKER_AMP_PRESENT BIT(14) 468c2ecf20Sopenharmony_ci#define SOF_MAX98360A_SPEAKER_AMP_PRESENT BIT(15) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* Default: MCLK on, MCLK 19.2M, SSP0 */ 498c2ecf20Sopenharmony_cistatic unsigned long sof_rt5682_quirk = SOF_RT5682_MCLK_EN | 508c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int is_legacy_cpu; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic struct snd_soc_jack sof_hdmi[3]; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistruct sof_hdmi_pcm { 578c2ecf20Sopenharmony_ci struct list_head head; 588c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai; 598c2ecf20Sopenharmony_ci int device; 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistruct sof_card_private { 638c2ecf20Sopenharmony_ci struct clk *mclk; 648c2ecf20Sopenharmony_ci struct snd_soc_jack sof_headset; 658c2ecf20Sopenharmony_ci struct list_head hdmi_pcm_list; 668c2ecf20Sopenharmony_ci bool common_hdmi_codec_drv; 678c2ecf20Sopenharmony_ci}; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int sof_rt5682_quirk_cb(const struct dmi_system_id *id) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci sof_rt5682_quirk = (unsigned long)id->driver_data; 728c2ecf20Sopenharmony_ci return 1; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic const struct dmi_system_id sof_rt5682_quirk_table[] = { 768c2ecf20Sopenharmony_ci { 778c2ecf20Sopenharmony_ci .callback = sof_rt5682_quirk_cb, 788c2ecf20Sopenharmony_ci .matches = { 798c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Circuitco"), 808c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Minnowboard Max"), 818c2ecf20Sopenharmony_ci }, 828c2ecf20Sopenharmony_ci .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), 838c2ecf20Sopenharmony_ci }, 848c2ecf20Sopenharmony_ci { 858c2ecf20Sopenharmony_ci .callback = sof_rt5682_quirk_cb, 868c2ecf20Sopenharmony_ci .matches = { 878c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "AAEON"), 888c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "UP-CHT01"), 898c2ecf20Sopenharmony_ci }, 908c2ecf20Sopenharmony_ci .driver_data = (void *)(SOF_RT5682_SSP_CODEC(2)), 918c2ecf20Sopenharmony_ci }, 928c2ecf20Sopenharmony_ci { 938c2ecf20Sopenharmony_ci .callback = sof_rt5682_quirk_cb, 948c2ecf20Sopenharmony_ci .matches = { 958c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 968c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "WhiskeyLake Client"), 978c2ecf20Sopenharmony_ci }, 988c2ecf20Sopenharmony_ci .driver_data = (void *)(SOF_RT5682_MCLK_EN | 998c2ecf20Sopenharmony_ci SOF_RT5682_MCLK_24MHZ | 1008c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(1)), 1018c2ecf20Sopenharmony_ci }, 1028c2ecf20Sopenharmony_ci { 1038c2ecf20Sopenharmony_ci .callback = sof_rt5682_quirk_cb, 1048c2ecf20Sopenharmony_ci .matches = { 1058c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Hatch"), 1068c2ecf20Sopenharmony_ci }, 1078c2ecf20Sopenharmony_ci .driver_data = (void *)(SOF_RT5682_MCLK_EN | 1088c2ecf20Sopenharmony_ci SOF_RT5682_MCLK_24MHZ | 1098c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0) | 1108c2ecf20Sopenharmony_ci SOF_SPEAKER_AMP_PRESENT | 1118c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP(1)), 1128c2ecf20Sopenharmony_ci }, 1138c2ecf20Sopenharmony_ci { 1148c2ecf20Sopenharmony_ci .callback = sof_rt5682_quirk_cb, 1158c2ecf20Sopenharmony_ci .matches = { 1168c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Intel Corporation"), 1178c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "Ice Lake Client"), 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci .driver_data = (void *)(SOF_RT5682_MCLK_EN | 1208c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0)), 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci .callback = sof_rt5682_quirk_cb, 1248c2ecf20Sopenharmony_ci .matches = { 1258c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "Google_Volteer"), 1268c2ecf20Sopenharmony_ci DMI_MATCH(DMI_OEM_STRING, "AUDIO-MAX98373_ALC5682I_I2S_UP4"), 1278c2ecf20Sopenharmony_ci }, 1288c2ecf20Sopenharmony_ci .driver_data = (void *)(SOF_RT5682_MCLK_EN | 1298c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0) | 1308c2ecf20Sopenharmony_ci SOF_SPEAKER_AMP_PRESENT | 1318c2ecf20Sopenharmony_ci SOF_MAX98373_SPEAKER_AMP_PRESENT | 1328c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP(2) | 1338c2ecf20Sopenharmony_ci SOF_RT5682_NUM_HDMIDEV(4)), 1348c2ecf20Sopenharmony_ci }, 1358c2ecf20Sopenharmony_ci {} 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int sof_hdmi_init(struct snd_soc_pcm_runtime *rtd) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 1418c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = asoc_rtd_to_codec(rtd, 0); 1428c2ecf20Sopenharmony_ci struct sof_hdmi_pcm *pcm; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci pcm = devm_kzalloc(rtd->card->dev, sizeof(*pcm), GFP_KERNEL); 1458c2ecf20Sopenharmony_ci if (!pcm) 1468c2ecf20Sopenharmony_ci return -ENOMEM; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* dai_link id is 1:1 mapped to the PCM device */ 1498c2ecf20Sopenharmony_ci pcm->device = rtd->dai_link->id; 1508c2ecf20Sopenharmony_ci pcm->codec_dai = dai; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci list_add_tail(&pcm->head, &ctx->hdmi_pcm_list); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic int sof_rt5682_codec_init(struct snd_soc_pcm_runtime *rtd) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 1608c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 1618c2ecf20Sopenharmony_ci struct snd_soc_jack *jack; 1628c2ecf20Sopenharmony_ci int ret; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci /* need to enable ASRC function for 24MHz mclk rate */ 1658c2ecf20Sopenharmony_ci if ((sof_rt5682_quirk & SOF_RT5682_MCLK_EN) && 1668c2ecf20Sopenharmony_ci (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ)) { 1678c2ecf20Sopenharmony_ci rt5682_sel_asrc_clk_src(component, RT5682_DA_STEREO1_FILTER | 1688c2ecf20Sopenharmony_ci RT5682_AD_STEREO1_FILTER, 1698c2ecf20Sopenharmony_ci RT5682_CLK_SEL_I2S1_ASRC); 1708c2ecf20Sopenharmony_ci } 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 1738c2ecf20Sopenharmony_ci /* 1748c2ecf20Sopenharmony_ci * The firmware might enable the clock at 1758c2ecf20Sopenharmony_ci * boot (this information may or may not 1768c2ecf20Sopenharmony_ci * be reflected in the enable clock register). 1778c2ecf20Sopenharmony_ci * To change the rate we must disable the clock 1788c2ecf20Sopenharmony_ci * first to cover these cases. Due to common 1798c2ecf20Sopenharmony_ci * clock framework restrictions that do not allow 1808c2ecf20Sopenharmony_ci * to disable a clock that has not been enabled, 1818c2ecf20Sopenharmony_ci * we need to enable the clock first. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ctx->mclk); 1848c2ecf20Sopenharmony_ci if (!ret) 1858c2ecf20Sopenharmony_ci clk_disable_unprepare(ctx->mclk); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci ret = clk_set_rate(ctx->mclk, 19200000); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (ret) 1908c2ecf20Sopenharmony_ci dev_err(rtd->dev, "unable to set MCLK rate\n"); 1918c2ecf20Sopenharmony_ci } 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci /* 1948c2ecf20Sopenharmony_ci * Headset buttons map to the google Reference headset. 1958c2ecf20Sopenharmony_ci * These can be configured by userspace. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_ci ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", 1988c2ecf20Sopenharmony_ci SND_JACK_HEADSET | SND_JACK_BTN_0 | 1998c2ecf20Sopenharmony_ci SND_JACK_BTN_1 | SND_JACK_BTN_2 | 2008c2ecf20Sopenharmony_ci SND_JACK_BTN_3, 2018c2ecf20Sopenharmony_ci &ctx->sof_headset, NULL, 0); 2028c2ecf20Sopenharmony_ci if (ret) { 2038c2ecf20Sopenharmony_ci dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); 2048c2ecf20Sopenharmony_ci return ret; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci jack = &ctx->sof_headset; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 2108c2ecf20Sopenharmony_ci snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 2118c2ecf20Sopenharmony_ci snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 2128c2ecf20Sopenharmony_ci snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 2138c2ecf20Sopenharmony_ci ret = snd_soc_component_set_jack(component, jack, NULL); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (ret) { 2168c2ecf20Sopenharmony_ci dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 2178c2ecf20Sopenharmony_ci return ret; 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return ret; 2218c2ecf20Sopenharmony_ci}; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic void sof_rt5682_codec_exit(struct snd_soc_pcm_runtime *rtd) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct snd_soc_component *component = asoc_rtd_to_codec(rtd, 0)->component; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci snd_soc_component_set_jack(component, NULL, NULL); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic int sof_rt5682_hw_params(struct snd_pcm_substream *substream, 2318c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2348c2ecf20Sopenharmony_ci struct sof_card_private *ctx = snd_soc_card_get_drvdata(rtd->card); 2358c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 2368c2ecf20Sopenharmony_ci int clk_id, clk_freq, pll_out, ret; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT5682_MCLK_EN) { 2398c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 2408c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ctx->mclk); 2418c2ecf20Sopenharmony_ci if (ret < 0) { 2428c2ecf20Sopenharmony_ci dev_err(rtd->dev, 2438c2ecf20Sopenharmony_ci "could not configure MCLK state"); 2448c2ecf20Sopenharmony_ci return ret; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci clk_id = RT5682_PLL1_S_MCLK; 2498c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT5682_MCLK_24MHZ) 2508c2ecf20Sopenharmony_ci clk_freq = 24000000; 2518c2ecf20Sopenharmony_ci else 2528c2ecf20Sopenharmony_ci clk_freq = 19200000; 2538c2ecf20Sopenharmony_ci } else { 2548c2ecf20Sopenharmony_ci clk_id = RT5682_PLL1_S_BCLK1; 2558c2ecf20Sopenharmony_ci clk_freq = params_rate(params) * 50; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci pll_out = params_rate(params) * 512; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, 0, clk_id, clk_freq, pll_out); 2618c2ecf20Sopenharmony_ci if (ret < 0) 2628c2ecf20Sopenharmony_ci dev_err(rtd->dev, "snd_soc_dai_set_pll err = %d\n", ret); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Configure sysclk for codec */ 2658c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL1, 2668c2ecf20Sopenharmony_ci pll_out, SND_SOC_CLOCK_IN); 2678c2ecf20Sopenharmony_ci if (ret < 0) 2688c2ecf20Sopenharmony_ci dev_err(rtd->dev, "snd_soc_dai_set_sysclk err = %d\n", ret); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* 2718c2ecf20Sopenharmony_ci * slot_width should equal or large than data length, set them 2728c2ecf20Sopenharmony_ci * be the same 2738c2ecf20Sopenharmony_ci */ 2748c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_tdm_slot(codec_dai, 0x0, 0x0, 2, 2758c2ecf20Sopenharmony_ci params_width(params)); 2768c2ecf20Sopenharmony_ci if (ret < 0) { 2778c2ecf20Sopenharmony_ci dev_err(rtd->dev, "set TDM slot err:%d\n", ret); 2788c2ecf20Sopenharmony_ci return ret; 2798c2ecf20Sopenharmony_ci } 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci return ret; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic struct snd_soc_ops sof_rt5682_ops = { 2858c2ecf20Sopenharmony_ci .hw_params = sof_rt5682_hw_params, 2868c2ecf20Sopenharmony_ci}; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic int sof_rt1015_hw_params(struct snd_pcm_substream *substream, 2898c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2928c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 2938c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai; 2948c2ecf20Sopenharmony_ci int i, ret; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (!snd_soc_card_get_codec_dai(card, "rt1015-aif")) 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 3008c2ecf20Sopenharmony_ci /* Set tdm/i2s1 master bclk ratio */ 3018c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); 3028c2ecf20Sopenharmony_ci if (ret < 0) { 3038c2ecf20Sopenharmony_ci dev_err(card->dev, "failed to set bclk ratio\n"); 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, 3088c2ecf20Sopenharmony_ci params_rate(params) * 64, 3098c2ecf20Sopenharmony_ci params_rate(params) * 256); 3108c2ecf20Sopenharmony_ci if (ret < 0) { 3118c2ecf20Sopenharmony_ci dev_err(card->dev, "failed to set pll\n"); 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci /* Configure sysclk for codec */ 3158c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, 3168c2ecf20Sopenharmony_ci params_rate(params) * 256, 3178c2ecf20Sopenharmony_ci SND_SOC_CLOCK_IN); 3188c2ecf20Sopenharmony_ci if (ret < 0) { 3198c2ecf20Sopenharmony_ci dev_err(card->dev, "failed to set sysclk\n"); 3208c2ecf20Sopenharmony_ci return ret; 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic struct snd_soc_ops sof_rt1015_ops = { 3288c2ecf20Sopenharmony_ci .hw_params = sof_rt1015_hw_params, 3298c2ecf20Sopenharmony_ci}; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link_component platform_component[] = { 3328c2ecf20Sopenharmony_ci { 3338c2ecf20Sopenharmony_ci /* name might be overridden during probe */ 3348c2ecf20Sopenharmony_ci .name = "0000:00:1f.3" 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci}; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int sof_card_late_probe(struct snd_soc_card *card) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct sof_card_private *ctx = snd_soc_card_get_drvdata(card); 3418c2ecf20Sopenharmony_ci struct snd_soc_component *component = NULL; 3428c2ecf20Sopenharmony_ci struct snd_soc_dapm_context *dapm = &card->dapm; 3438c2ecf20Sopenharmony_ci char jack_name[NAME_SIZE]; 3448c2ecf20Sopenharmony_ci struct sof_hdmi_pcm *pcm; 3458c2ecf20Sopenharmony_ci int err; 3468c2ecf20Sopenharmony_ci int i = 0; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* HDMI is not supported by SOF on Baytrail/CherryTrail */ 3498c2ecf20Sopenharmony_ci if (is_legacy_cpu) 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci if (list_empty(&ctx->hdmi_pcm_list)) 3538c2ecf20Sopenharmony_ci return -EINVAL; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (ctx->common_hdmi_codec_drv) { 3568c2ecf20Sopenharmony_ci pcm = list_first_entry(&ctx->hdmi_pcm_list, struct sof_hdmi_pcm, 3578c2ecf20Sopenharmony_ci head); 3588c2ecf20Sopenharmony_ci component = pcm->codec_dai->component; 3598c2ecf20Sopenharmony_ci return hda_dsp_hdmi_build_controls(card, component); 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci list_for_each_entry(pcm, &ctx->hdmi_pcm_list, head) { 3638c2ecf20Sopenharmony_ci component = pcm->codec_dai->component; 3648c2ecf20Sopenharmony_ci snprintf(jack_name, sizeof(jack_name), 3658c2ecf20Sopenharmony_ci "HDMI/DP, pcm=%d Jack", pcm->device); 3668c2ecf20Sopenharmony_ci err = snd_soc_card_jack_new(card, jack_name, 3678c2ecf20Sopenharmony_ci SND_JACK_AVOUT, &sof_hdmi[i], 3688c2ecf20Sopenharmony_ci NULL, 0); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (err) 3718c2ecf20Sopenharmony_ci return err; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci err = hdac_hdmi_jack_init(pcm->codec_dai, pcm->device, 3748c2ecf20Sopenharmony_ci &sof_hdmi[i]); 3758c2ecf20Sopenharmony_ci if (err < 0) 3768c2ecf20Sopenharmony_ci return err; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci i++; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) { 3828c2ecf20Sopenharmony_ci /* Disable Left and Right Spk pin after boot */ 3838c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "Left Spk"); 3848c2ecf20Sopenharmony_ci snd_soc_dapm_disable_pin(dapm, "Right Spk"); 3858c2ecf20Sopenharmony_ci err = snd_soc_dapm_sync(dapm); 3868c2ecf20Sopenharmony_ci if (err < 0) 3878c2ecf20Sopenharmony_ci return err; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci return hdac_hdmi_jack_port_init(component, &card->dapm); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new sof_controls[] = { 3938c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headphone Jack"), 3948c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 3958c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Spk"), 3968c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Left Spk"), 3978c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Right Spk"), 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci}; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget sof_widgets[] = { 4028c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", NULL), 4038c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 4048c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Spk", NULL), 4058c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Left Spk", NULL), 4068c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Right Spk", NULL), 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget dmic_widgets[] = { 4108c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("SoC DMIC", NULL), 4118c2ecf20Sopenharmony_ci}; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route sof_map[] = { 4148c2ecf20Sopenharmony_ci /* HP jack connectors - unknown if we have jack detection */ 4158c2ecf20Sopenharmony_ci { "Headphone Jack", NULL, "HPOL" }, 4168c2ecf20Sopenharmony_ci { "Headphone Jack", NULL, "HPOR" }, 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* other jacks */ 4198c2ecf20Sopenharmony_ci { "IN1P", NULL, "Headset Mic" }, 4208c2ecf20Sopenharmony_ci}; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route speaker_map[] = { 4238c2ecf20Sopenharmony_ci /* speaker */ 4248c2ecf20Sopenharmony_ci { "Spk", NULL, "Speaker" }, 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route speaker_map_lr[] = { 4288c2ecf20Sopenharmony_ci { "Left Spk", NULL, "Left SPO" }, 4298c2ecf20Sopenharmony_ci { "Right Spk", NULL, "Right SPO" }, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route dmic_map[] = { 4338c2ecf20Sopenharmony_ci /* digital mics */ 4348c2ecf20Sopenharmony_ci {"DMic", NULL, "SoC DMIC"}, 4358c2ecf20Sopenharmony_ci}; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int speaker_codec_init_lr(struct snd_soc_pcm_runtime *rtd) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci return snd_soc_dapm_add_routes(&rtd->card->dapm, speaker_map_lr, 4408c2ecf20Sopenharmony_ci ARRAY_SIZE(speaker_map_lr)); 4418c2ecf20Sopenharmony_ci} 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic int speaker_codec_init(struct snd_soc_pcm_runtime *rtd) 4448c2ecf20Sopenharmony_ci{ 4458c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 4468c2ecf20Sopenharmony_ci int ret; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(&card->dapm, speaker_map, 4498c2ecf20Sopenharmony_ci ARRAY_SIZE(speaker_map)); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci if (ret) 4528c2ecf20Sopenharmony_ci dev_err(rtd->dev, "Speaker map addition failed: %d\n", ret); 4538c2ecf20Sopenharmony_ci return ret; 4548c2ecf20Sopenharmony_ci} 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistatic int dmic_init(struct snd_soc_pcm_runtime *rtd) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 4598c2ecf20Sopenharmony_ci int ret; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci ret = snd_soc_dapm_new_controls(&card->dapm, dmic_widgets, 4628c2ecf20Sopenharmony_ci ARRAY_SIZE(dmic_widgets)); 4638c2ecf20Sopenharmony_ci if (ret) { 4648c2ecf20Sopenharmony_ci dev_err(card->dev, "DMic widget addition failed: %d\n", ret); 4658c2ecf20Sopenharmony_ci /* Don't need to add routes if widget addition failed */ 4668c2ecf20Sopenharmony_ci return ret; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci ret = snd_soc_dapm_add_routes(&card->dapm, dmic_map, 4708c2ecf20Sopenharmony_ci ARRAY_SIZE(dmic_map)); 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci if (ret) 4738c2ecf20Sopenharmony_ci dev_err(card->dev, "DMic map addition failed: %d\n", ret); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return ret; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic struct snd_soc_codec_conf rt1015_amp_conf[] = { 4798c2ecf20Sopenharmony_ci { 4808c2ecf20Sopenharmony_ci .dlc = COMP_CODEC_CONF("i2c-10EC1015:00"), 4818c2ecf20Sopenharmony_ci .name_prefix = "Left", 4828c2ecf20Sopenharmony_ci }, 4838c2ecf20Sopenharmony_ci { 4848c2ecf20Sopenharmony_ci .dlc = COMP_CODEC_CONF("i2c-10EC1015:01"), 4858c2ecf20Sopenharmony_ci .name_prefix = "Right", 4868c2ecf20Sopenharmony_ci }, 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci/* sof audio machine driver for rt5682 codec */ 4908c2ecf20Sopenharmony_cistatic struct snd_soc_card sof_audio_card_rt5682 = { 4918c2ecf20Sopenharmony_ci .name = "rt5682", /* the sof- prefix is added by the core */ 4928c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4938c2ecf20Sopenharmony_ci .controls = sof_controls, 4948c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(sof_controls), 4958c2ecf20Sopenharmony_ci .dapm_widgets = sof_widgets, 4968c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(sof_widgets), 4978c2ecf20Sopenharmony_ci .dapm_routes = sof_map, 4988c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(sof_map), 4998c2ecf20Sopenharmony_ci .fully_routed = true, 5008c2ecf20Sopenharmony_ci .late_probe = sof_card_late_probe, 5018c2ecf20Sopenharmony_ci}; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link_component rt5682_component[] = { 5048c2ecf20Sopenharmony_ci { 5058c2ecf20Sopenharmony_ci .name = "i2c-10EC5682:00", 5068c2ecf20Sopenharmony_ci .dai_name = "rt5682-aif1", 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link_component dmic_component[] = { 5118c2ecf20Sopenharmony_ci { 5128c2ecf20Sopenharmony_ci .name = "dmic-codec", 5138c2ecf20Sopenharmony_ci .dai_name = "dmic-hifi", 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci}; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link_component max98357a_component[] = { 5188c2ecf20Sopenharmony_ci { 5198c2ecf20Sopenharmony_ci .name = "MX98357A:00", 5208c2ecf20Sopenharmony_ci .dai_name = "HiFi", 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci}; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link_component max98360a_component[] = { 5258c2ecf20Sopenharmony_ci { 5268c2ecf20Sopenharmony_ci .name = "MX98360A:00", 5278c2ecf20Sopenharmony_ci .dai_name = "HiFi", 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci}; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link_component rt1015_components[] = { 5328c2ecf20Sopenharmony_ci { 5338c2ecf20Sopenharmony_ci .name = "i2c-10EC1015:00", 5348c2ecf20Sopenharmony_ci .dai_name = "rt1015-aif", 5358c2ecf20Sopenharmony_ci }, 5368c2ecf20Sopenharmony_ci { 5378c2ecf20Sopenharmony_ci .name = "i2c-10EC1015:01", 5388c2ecf20Sopenharmony_ci .dai_name = "rt1015-aif", 5398c2ecf20Sopenharmony_ci }, 5408c2ecf20Sopenharmony_ci}; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link *sof_card_dai_links_create(struct device *dev, 5438c2ecf20Sopenharmony_ci int ssp_codec, 5448c2ecf20Sopenharmony_ci int ssp_amp, 5458c2ecf20Sopenharmony_ci int dmic_be_num, 5468c2ecf20Sopenharmony_ci int hdmi_num) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct snd_soc_dai_link_component *idisp_components; 5498c2ecf20Sopenharmony_ci struct snd_soc_dai_link_component *cpus; 5508c2ecf20Sopenharmony_ci struct snd_soc_dai_link *links; 5518c2ecf20Sopenharmony_ci int i, id = 0; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci links = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link) * 5548c2ecf20Sopenharmony_ci sof_audio_card_rt5682.num_links, GFP_KERNEL); 5558c2ecf20Sopenharmony_ci cpus = devm_kzalloc(dev, sizeof(struct snd_soc_dai_link_component) * 5568c2ecf20Sopenharmony_ci sof_audio_card_rt5682.num_links, GFP_KERNEL); 5578c2ecf20Sopenharmony_ci if (!links || !cpus) 5588c2ecf20Sopenharmony_ci goto devm_err; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci /* codec SSP */ 5618c2ecf20Sopenharmony_ci links[id].name = devm_kasprintf(dev, GFP_KERNEL, 5628c2ecf20Sopenharmony_ci "SSP%d-Codec", ssp_codec); 5638c2ecf20Sopenharmony_ci if (!links[id].name) 5648c2ecf20Sopenharmony_ci goto devm_err; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci links[id].id = id; 5678c2ecf20Sopenharmony_ci links[id].codecs = rt5682_component; 5688c2ecf20Sopenharmony_ci links[id].num_codecs = ARRAY_SIZE(rt5682_component); 5698c2ecf20Sopenharmony_ci links[id].platforms = platform_component; 5708c2ecf20Sopenharmony_ci links[id].num_platforms = ARRAY_SIZE(platform_component); 5718c2ecf20Sopenharmony_ci links[id].init = sof_rt5682_codec_init; 5728c2ecf20Sopenharmony_ci links[id].exit = sof_rt5682_codec_exit; 5738c2ecf20Sopenharmony_ci links[id].ops = &sof_rt5682_ops; 5748c2ecf20Sopenharmony_ci links[id].nonatomic = true; 5758c2ecf20Sopenharmony_ci links[id].dpcm_playback = 1; 5768c2ecf20Sopenharmony_ci links[id].dpcm_capture = 1; 5778c2ecf20Sopenharmony_ci links[id].no_pcm = 1; 5788c2ecf20Sopenharmony_ci links[id].cpus = &cpus[id]; 5798c2ecf20Sopenharmony_ci links[id].num_cpus = 1; 5808c2ecf20Sopenharmony_ci if (is_legacy_cpu) { 5818c2ecf20Sopenharmony_ci links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 5828c2ecf20Sopenharmony_ci "ssp%d-port", 5838c2ecf20Sopenharmony_ci ssp_codec); 5848c2ecf20Sopenharmony_ci if (!links[id].cpus->dai_name) 5858c2ecf20Sopenharmony_ci goto devm_err; 5868c2ecf20Sopenharmony_ci } else { 5878c2ecf20Sopenharmony_ci /* 5888c2ecf20Sopenharmony_ci * Currently, On SKL+ platforms MCLK will be turned off in sof 5898c2ecf20Sopenharmony_ci * runtime suspended, and it will go into runtime suspended 5908c2ecf20Sopenharmony_ci * right after playback is stop. However, rt5682 will output 5918c2ecf20Sopenharmony_ci * static noise if sysclk turns off during playback. Set 5928c2ecf20Sopenharmony_ci * ignore_pmdown_time to power down rt5682 immediately and 5938c2ecf20Sopenharmony_ci * avoid the noise. 5948c2ecf20Sopenharmony_ci * It can be removed once we can control MCLK by driver. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci links[id].ignore_pmdown_time = 1; 5978c2ecf20Sopenharmony_ci links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 5988c2ecf20Sopenharmony_ci "SSP%d Pin", 5998c2ecf20Sopenharmony_ci ssp_codec); 6008c2ecf20Sopenharmony_ci if (!links[id].cpus->dai_name) 6018c2ecf20Sopenharmony_ci goto devm_err; 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci id++; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci /* dmic */ 6068c2ecf20Sopenharmony_ci if (dmic_be_num > 0) { 6078c2ecf20Sopenharmony_ci /* at least we have dmic01 */ 6088c2ecf20Sopenharmony_ci links[id].name = "dmic01"; 6098c2ecf20Sopenharmony_ci links[id].cpus = &cpus[id]; 6108c2ecf20Sopenharmony_ci links[id].cpus->dai_name = "DMIC01 Pin"; 6118c2ecf20Sopenharmony_ci links[id].init = dmic_init; 6128c2ecf20Sopenharmony_ci if (dmic_be_num > 1) { 6138c2ecf20Sopenharmony_ci /* set up 2 BE links at most */ 6148c2ecf20Sopenharmony_ci links[id + 1].name = "dmic16k"; 6158c2ecf20Sopenharmony_ci links[id + 1].cpus = &cpus[id + 1]; 6168c2ecf20Sopenharmony_ci links[id + 1].cpus->dai_name = "DMIC16k Pin"; 6178c2ecf20Sopenharmony_ci dmic_be_num = 2; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci for (i = 0; i < dmic_be_num; i++) { 6228c2ecf20Sopenharmony_ci links[id].id = id; 6238c2ecf20Sopenharmony_ci links[id].num_cpus = 1; 6248c2ecf20Sopenharmony_ci links[id].codecs = dmic_component; 6258c2ecf20Sopenharmony_ci links[id].num_codecs = ARRAY_SIZE(dmic_component); 6268c2ecf20Sopenharmony_ci links[id].platforms = platform_component; 6278c2ecf20Sopenharmony_ci links[id].num_platforms = ARRAY_SIZE(platform_component); 6288c2ecf20Sopenharmony_ci links[id].ignore_suspend = 1; 6298c2ecf20Sopenharmony_ci links[id].dpcm_capture = 1; 6308c2ecf20Sopenharmony_ci links[id].no_pcm = 1; 6318c2ecf20Sopenharmony_ci id++; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci /* HDMI */ 6358c2ecf20Sopenharmony_ci if (hdmi_num > 0) { 6368c2ecf20Sopenharmony_ci idisp_components = devm_kzalloc(dev, 6378c2ecf20Sopenharmony_ci sizeof(struct snd_soc_dai_link_component) * 6388c2ecf20Sopenharmony_ci hdmi_num, GFP_KERNEL); 6398c2ecf20Sopenharmony_ci if (!idisp_components) 6408c2ecf20Sopenharmony_ci goto devm_err; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci for (i = 1; i <= hdmi_num; i++) { 6438c2ecf20Sopenharmony_ci links[id].name = devm_kasprintf(dev, GFP_KERNEL, 6448c2ecf20Sopenharmony_ci "iDisp%d", i); 6458c2ecf20Sopenharmony_ci if (!links[id].name) 6468c2ecf20Sopenharmony_ci goto devm_err; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci links[id].id = id; 6498c2ecf20Sopenharmony_ci links[id].cpus = &cpus[id]; 6508c2ecf20Sopenharmony_ci links[id].num_cpus = 1; 6518c2ecf20Sopenharmony_ci links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 6528c2ecf20Sopenharmony_ci "iDisp%d Pin", i); 6538c2ecf20Sopenharmony_ci if (!links[id].cpus->dai_name) 6548c2ecf20Sopenharmony_ci goto devm_err; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci idisp_components[i - 1].name = "ehdaudio0D2"; 6578c2ecf20Sopenharmony_ci idisp_components[i - 1].dai_name = devm_kasprintf(dev, 6588c2ecf20Sopenharmony_ci GFP_KERNEL, 6598c2ecf20Sopenharmony_ci "intel-hdmi-hifi%d", 6608c2ecf20Sopenharmony_ci i); 6618c2ecf20Sopenharmony_ci if (!idisp_components[i - 1].dai_name) 6628c2ecf20Sopenharmony_ci goto devm_err; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci links[id].codecs = &idisp_components[i - 1]; 6658c2ecf20Sopenharmony_ci links[id].num_codecs = 1; 6668c2ecf20Sopenharmony_ci links[id].platforms = platform_component; 6678c2ecf20Sopenharmony_ci links[id].num_platforms = ARRAY_SIZE(platform_component); 6688c2ecf20Sopenharmony_ci links[id].init = sof_hdmi_init; 6698c2ecf20Sopenharmony_ci links[id].dpcm_playback = 1; 6708c2ecf20Sopenharmony_ci links[id].no_pcm = 1; 6718c2ecf20Sopenharmony_ci id++; 6728c2ecf20Sopenharmony_ci } 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* speaker amp */ 6758c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) { 6768c2ecf20Sopenharmony_ci links[id].name = devm_kasprintf(dev, GFP_KERNEL, 6778c2ecf20Sopenharmony_ci "SSP%d-Codec", ssp_amp); 6788c2ecf20Sopenharmony_ci if (!links[id].name) 6798c2ecf20Sopenharmony_ci goto devm_err; 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci links[id].id = id; 6828c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) { 6838c2ecf20Sopenharmony_ci links[id].codecs = rt1015_components; 6848c2ecf20Sopenharmony_ci links[id].num_codecs = ARRAY_SIZE(rt1015_components); 6858c2ecf20Sopenharmony_ci links[id].init = speaker_codec_init_lr; 6868c2ecf20Sopenharmony_ci links[id].ops = &sof_rt1015_ops; 6878c2ecf20Sopenharmony_ci } else if (sof_rt5682_quirk & 6888c2ecf20Sopenharmony_ci SOF_MAX98373_SPEAKER_AMP_PRESENT) { 6898c2ecf20Sopenharmony_ci links[id].codecs = max_98373_components; 6908c2ecf20Sopenharmony_ci links[id].num_codecs = ARRAY_SIZE(max_98373_components); 6918c2ecf20Sopenharmony_ci links[id].init = max98373_spk_codec_init; 6928c2ecf20Sopenharmony_ci links[id].ops = &max_98373_ops; 6938c2ecf20Sopenharmony_ci } else if (sof_rt5682_quirk & 6948c2ecf20Sopenharmony_ci SOF_MAX98360A_SPEAKER_AMP_PRESENT) { 6958c2ecf20Sopenharmony_ci links[id].codecs = max98360a_component; 6968c2ecf20Sopenharmony_ci links[id].num_codecs = ARRAY_SIZE(max98360a_component); 6978c2ecf20Sopenharmony_ci links[id].init = speaker_codec_init; 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci links[id].codecs = max98357a_component; 7008c2ecf20Sopenharmony_ci links[id].num_codecs = ARRAY_SIZE(max98357a_component); 7018c2ecf20Sopenharmony_ci links[id].init = speaker_codec_init; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci links[id].platforms = platform_component; 7048c2ecf20Sopenharmony_ci links[id].num_platforms = ARRAY_SIZE(platform_component); 7058c2ecf20Sopenharmony_ci links[id].nonatomic = true; 7068c2ecf20Sopenharmony_ci links[id].dpcm_playback = 1; 7078c2ecf20Sopenharmony_ci /* feedback stream or firmware-generated echo reference */ 7088c2ecf20Sopenharmony_ci links[id].dpcm_capture = 1; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci links[id].no_pcm = 1; 7118c2ecf20Sopenharmony_ci links[id].cpus = &cpus[id]; 7128c2ecf20Sopenharmony_ci links[id].num_cpus = 1; 7138c2ecf20Sopenharmony_ci if (is_legacy_cpu) { 7148c2ecf20Sopenharmony_ci links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 7158c2ecf20Sopenharmony_ci "ssp%d-port", 7168c2ecf20Sopenharmony_ci ssp_amp); 7178c2ecf20Sopenharmony_ci if (!links[id].cpus->dai_name) 7188c2ecf20Sopenharmony_ci goto devm_err; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci } else { 7218c2ecf20Sopenharmony_ci links[id].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, 7228c2ecf20Sopenharmony_ci "SSP%d Pin", 7238c2ecf20Sopenharmony_ci ssp_amp); 7248c2ecf20Sopenharmony_ci if (!links[id].cpus->dai_name) 7258c2ecf20Sopenharmony_ci goto devm_err; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return links; 7308c2ecf20Sopenharmony_cidevm_err: 7318c2ecf20Sopenharmony_ci return NULL; 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic int sof_audio_probe(struct platform_device *pdev) 7358c2ecf20Sopenharmony_ci{ 7368c2ecf20Sopenharmony_ci struct snd_soc_dai_link *dai_links; 7378c2ecf20Sopenharmony_ci struct snd_soc_acpi_mach *mach; 7388c2ecf20Sopenharmony_ci struct sof_card_private *ctx; 7398c2ecf20Sopenharmony_ci int dmic_be_num, hdmi_num; 7408c2ecf20Sopenharmony_ci int ret, ssp_amp, ssp_codec; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); 7438c2ecf20Sopenharmony_ci if (!ctx) 7448c2ecf20Sopenharmony_ci return -ENOMEM; 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci if (pdev->id_entry && pdev->id_entry->driver_data) 7478c2ecf20Sopenharmony_ci sof_rt5682_quirk = (unsigned long)pdev->id_entry->driver_data; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci dmi_check_system(sof_rt5682_quirk_table); 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci mach = pdev->dev.platform_data; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* A speaker amp might not be present when the quirk claims one is. 7548c2ecf20Sopenharmony_ci * Detect this via whether the machine driver match includes quirk_data. 7558c2ecf20Sopenharmony_ci */ 7568c2ecf20Sopenharmony_ci if ((sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) && !mach->quirk_data) 7578c2ecf20Sopenharmony_ci sof_rt5682_quirk &= ~SOF_SPEAKER_AMP_PRESENT; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci if (soc_intel_is_byt() || soc_intel_is_cht()) { 7608c2ecf20Sopenharmony_ci is_legacy_cpu = 1; 7618c2ecf20Sopenharmony_ci dmic_be_num = 0; 7628c2ecf20Sopenharmony_ci hdmi_num = 0; 7638c2ecf20Sopenharmony_ci /* default quirk for legacy cpu */ 7648c2ecf20Sopenharmony_ci sof_rt5682_quirk = SOF_RT5682_MCLK_EN | 7658c2ecf20Sopenharmony_ci SOF_RT5682_MCLK_BYTCHT_EN | 7668c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(2); 7678c2ecf20Sopenharmony_ci } else { 7688c2ecf20Sopenharmony_ci dmic_be_num = 2; 7698c2ecf20Sopenharmony_ci hdmi_num = (sof_rt5682_quirk & SOF_RT5682_NUM_HDMIDEV_MASK) >> 7708c2ecf20Sopenharmony_ci SOF_RT5682_NUM_HDMIDEV_SHIFT; 7718c2ecf20Sopenharmony_ci /* default number of HDMI DAI's */ 7728c2ecf20Sopenharmony_ci if (!hdmi_num) 7738c2ecf20Sopenharmony_ci hdmi_num = 3; 7748c2ecf20Sopenharmony_ci } 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci /* need to get main clock from pmc */ 7778c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT5682_MCLK_BYTCHT_EN) { 7788c2ecf20Sopenharmony_ci ctx->mclk = devm_clk_get(&pdev->dev, "pmc_plt_clk_3"); 7798c2ecf20Sopenharmony_ci if (IS_ERR(ctx->mclk)) { 7808c2ecf20Sopenharmony_ci ret = PTR_ERR(ctx->mclk); 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7838c2ecf20Sopenharmony_ci "Failed to get MCLK from pmc_plt_clk_3: %d\n", 7848c2ecf20Sopenharmony_ci ret); 7858c2ecf20Sopenharmony_ci return ret; 7868c2ecf20Sopenharmony_ci } 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = clk_prepare_enable(ctx->mclk); 7898c2ecf20Sopenharmony_ci if (ret < 0) { 7908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 7918c2ecf20Sopenharmony_ci "could not configure MCLK state"); 7928c2ecf20Sopenharmony_ci return ret; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci } 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "sof_rt5682_quirk = %lx\n", sof_rt5682_quirk); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci ssp_amp = (sof_rt5682_quirk & SOF_RT5682_SSP_AMP_MASK) >> 7998c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP_SHIFT; 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci ssp_codec = sof_rt5682_quirk & SOF_RT5682_SSP_CODEC_MASK; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci /* compute number of dai links */ 8048c2ecf20Sopenharmony_ci sof_audio_card_rt5682.num_links = 1 + dmic_be_num + hdmi_num; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_SPEAKER_AMP_PRESENT) 8078c2ecf20Sopenharmony_ci sof_audio_card_rt5682.num_links++; 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_MAX98373_SPEAKER_AMP_PRESENT) 8108c2ecf20Sopenharmony_ci sof_max98373_codec_conf(&sof_audio_card_rt5682); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci dai_links = sof_card_dai_links_create(&pdev->dev, ssp_codec, ssp_amp, 8138c2ecf20Sopenharmony_ci dmic_be_num, hdmi_num); 8148c2ecf20Sopenharmony_ci if (!dai_links) 8158c2ecf20Sopenharmony_ci return -ENOMEM; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci sof_audio_card_rt5682.dai_link = dai_links; 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci if (sof_rt5682_quirk & SOF_RT1015_SPEAKER_AMP_PRESENT) { 8208c2ecf20Sopenharmony_ci sof_audio_card_rt5682.codec_conf = rt1015_amp_conf; 8218c2ecf20Sopenharmony_ci sof_audio_card_rt5682.num_configs = ARRAY_SIZE(rt1015_amp_conf); 8228c2ecf20Sopenharmony_ci } 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctx->hdmi_pcm_list); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci sof_audio_card_rt5682.dev = &pdev->dev; 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci /* set platform name for each dailink */ 8298c2ecf20Sopenharmony_ci ret = snd_soc_fixup_dai_links_platform_name(&sof_audio_card_rt5682, 8308c2ecf20Sopenharmony_ci mach->mach_params.platform); 8318c2ecf20Sopenharmony_ci if (ret) 8328c2ecf20Sopenharmony_ci return ret; 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(&sof_audio_card_rt5682, ctx); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci return devm_snd_soc_register_card(&pdev->dev, 8398c2ecf20Sopenharmony_ci &sof_audio_card_rt5682); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_cistatic const struct platform_device_id board_ids[] = { 8438c2ecf20Sopenharmony_ci { 8448c2ecf20Sopenharmony_ci .name = "sof_rt5682", 8458c2ecf20Sopenharmony_ci }, 8468c2ecf20Sopenharmony_ci { 8478c2ecf20Sopenharmony_ci .name = "tgl_max98357a_rt5682", 8488c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | 8498c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0) | 8508c2ecf20Sopenharmony_ci SOF_SPEAKER_AMP_PRESENT | 8518c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP(1) | 8528c2ecf20Sopenharmony_ci SOF_RT5682_NUM_HDMIDEV(4)), 8538c2ecf20Sopenharmony_ci }, 8548c2ecf20Sopenharmony_ci { 8558c2ecf20Sopenharmony_ci .name = "jsl_rt5682_rt1015", 8568c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | 8578c2ecf20Sopenharmony_ci SOF_RT5682_MCLK_24MHZ | 8588c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0) | 8598c2ecf20Sopenharmony_ci SOF_SPEAKER_AMP_PRESENT | 8608c2ecf20Sopenharmony_ci SOF_RT1015_SPEAKER_AMP_PRESENT | 8618c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP(1)), 8628c2ecf20Sopenharmony_ci }, 8638c2ecf20Sopenharmony_ci { 8648c2ecf20Sopenharmony_ci .name = "tgl_max98373_rt5682", 8658c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | 8668c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0) | 8678c2ecf20Sopenharmony_ci SOF_SPEAKER_AMP_PRESENT | 8688c2ecf20Sopenharmony_ci SOF_MAX98373_SPEAKER_AMP_PRESENT | 8698c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP(1) | 8708c2ecf20Sopenharmony_ci SOF_RT5682_NUM_HDMIDEV(4)), 8718c2ecf20Sopenharmony_ci }, 8728c2ecf20Sopenharmony_ci { 8738c2ecf20Sopenharmony_ci .name = "jsl_rt5682_max98360a", 8748c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)(SOF_RT5682_MCLK_EN | 8758c2ecf20Sopenharmony_ci SOF_RT5682_MCLK_24MHZ | 8768c2ecf20Sopenharmony_ci SOF_RT5682_SSP_CODEC(0) | 8778c2ecf20Sopenharmony_ci SOF_SPEAKER_AMP_PRESENT | 8788c2ecf20Sopenharmony_ci SOF_MAX98360A_SPEAKER_AMP_PRESENT | 8798c2ecf20Sopenharmony_ci SOF_RT5682_SSP_AMP(1)), 8808c2ecf20Sopenharmony_ci }, 8818c2ecf20Sopenharmony_ci { } 8828c2ecf20Sopenharmony_ci}; 8838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(platform, board_ids); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_cistatic struct platform_driver sof_audio = { 8868c2ecf20Sopenharmony_ci .probe = sof_audio_probe, 8878c2ecf20Sopenharmony_ci .driver = { 8888c2ecf20Sopenharmony_ci .name = "sof_rt5682", 8898c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 8908c2ecf20Sopenharmony_ci }, 8918c2ecf20Sopenharmony_ci .id_table = board_ids, 8928c2ecf20Sopenharmony_ci}; 8938c2ecf20Sopenharmony_cimodule_platform_driver(sof_audio) 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci/* Module information */ 8968c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SOF Audio Machine driver"); 8978c2ecf20Sopenharmony_ciMODULE_AUTHOR("Bard Liao <bard.liao@intel.com>"); 8988c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); 8998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 9008c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:sof_rt5682"); 9018c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:tgl_max98357a_rt5682"); 9028c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:jsl_rt5682_rt1015"); 9038c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:tgl_max98373_rt5682"); 9048c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:jsl_rt5682_max98360a"); 905