18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec. 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci//Copyright 2016 Advanced Micro Devices, Inc. 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <sound/core.h> 88c2ecf20Sopenharmony_ci#include <sound/soc.h> 98c2ecf20Sopenharmony_ci#include <sound/pcm.h> 108c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 118c2ecf20Sopenharmony_ci#include <sound/soc-dapm.h> 128c2ecf20Sopenharmony_ci#include <sound/jack.h> 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/gpio.h> 158c2ecf20Sopenharmony_ci#include <linux/gpio/consumer.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/i2c.h> 188c2ecf20Sopenharmony_ci#include <linux/input.h> 198c2ecf20Sopenharmony_ci#include <linux/io.h> 208c2ecf20Sopenharmony_ci#include <linux/acpi.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "raven/acp3x.h" 238c2ecf20Sopenharmony_ci#include "../codecs/rt5682.h" 248c2ecf20Sopenharmony_ci#include "../codecs/rt1015.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define PCO_PLAT_CLK 48000000 278c2ecf20Sopenharmony_ci#define RT5682_PLL_FREQ (48000 * 512) 288c2ecf20Sopenharmony_ci#define DUAL_CHANNEL 2 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic struct snd_soc_jack pco_jack; 318c2ecf20Sopenharmony_cistatic struct clk *rt5682_dai_wclk; 328c2ecf20Sopenharmony_cistatic struct clk *rt5682_dai_bclk; 338c2ecf20Sopenharmony_cistatic struct gpio_desc *dmic_sel; 348c2ecf20Sopenharmony_civoid *soc_is_rltk_max(struct device *dev); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cienum { 378c2ecf20Sopenharmony_ci RT5682 = 0, 388c2ecf20Sopenharmony_ci MAX, 398c2ecf20Sopenharmony_ci EC, 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int ret; 458c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 468c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 478c2ecf20Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci /* set rt5682 dai fmt */ 528c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S 538c2ecf20Sopenharmony_ci | SND_SOC_DAIFMT_NB_NF 548c2ecf20Sopenharmony_ci | SND_SOC_DAIFMT_CBM_CFM); 558c2ecf20Sopenharmony_ci if (ret < 0) { 568c2ecf20Sopenharmony_ci dev_err(rtd->card->dev, 578c2ecf20Sopenharmony_ci "Failed to set rt5682 dai fmt: %d\n", ret); 588c2ecf20Sopenharmony_ci return ret; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* set codec PLL */ 628c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK, 638c2ecf20Sopenharmony_ci PCO_PLAT_CLK, RT5682_PLL_FREQ); 648c2ecf20Sopenharmony_ci if (ret < 0) { 658c2ecf20Sopenharmony_ci dev_err(rtd->dev, "can't set rt5682 PLL: %d\n", ret); 668c2ecf20Sopenharmony_ci return ret; 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* Set codec sysclk */ 708c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2, 718c2ecf20Sopenharmony_ci RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); 728c2ecf20Sopenharmony_ci if (ret < 0) { 738c2ecf20Sopenharmony_ci dev_err(rtd->dev, 748c2ecf20Sopenharmony_ci "Failed to set rt5682 SYSCLK: %d\n", ret); 758c2ecf20Sopenharmony_ci return ret; 768c2ecf20Sopenharmony_ci } 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* Set tdm/i2s1 master bclk ratio */ 798c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); 808c2ecf20Sopenharmony_ci if (ret < 0) { 818c2ecf20Sopenharmony_ci dev_err(rtd->dev, 828c2ecf20Sopenharmony_ci "Failed to set rt5682 tdm bclk ratio: %d\n", ret); 838c2ecf20Sopenharmony_ci return ret; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk"); 878c2ecf20Sopenharmony_ci rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci ret = snd_soc_card_jack_new(card, "Headset Jack", 908c2ecf20Sopenharmony_ci SND_JACK_HEADSET | SND_JACK_LINEOUT | 918c2ecf20Sopenharmony_ci SND_JACK_BTN_0 | SND_JACK_BTN_1 | 928c2ecf20Sopenharmony_ci SND_JACK_BTN_2 | SND_JACK_BTN_3, 938c2ecf20Sopenharmony_ci &pco_jack, NULL, 0); 948c2ecf20Sopenharmony_ci if (ret) { 958c2ecf20Sopenharmony_ci dev_err(card->dev, "HP jack creation failed %d\n", ret); 968c2ecf20Sopenharmony_ci return ret; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 1008c2ecf20Sopenharmony_ci snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOICECOMMAND); 1018c2ecf20Sopenharmony_ci snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEUP); 1028c2ecf20Sopenharmony_ci snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci ret = snd_soc_component_set_jack(component, &pco_jack, NULL); 1058c2ecf20Sopenharmony_ci if (ret) { 1068c2ecf20Sopenharmony_ci dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 1078c2ecf20Sopenharmony_ci return ret; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci return ret; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic int rt5682_clk_enable(struct snd_pcm_substream *substream) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci int ret = 0; 1168c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* RT5682 will support only 48K output with 48M mclk */ 1198c2ecf20Sopenharmony_ci clk_set_rate(rt5682_dai_wclk, 48000); 1208c2ecf20Sopenharmony_ci clk_set_rate(rt5682_dai_bclk, 48000 * 64); 1218c2ecf20Sopenharmony_ci ret = clk_prepare_enable(rt5682_dai_wclk); 1228c2ecf20Sopenharmony_ci if (ret < 0) { 1238c2ecf20Sopenharmony_ci dev_err(rtd->dev, "can't enable wclk %d\n", ret); 1248c2ecf20Sopenharmony_ci return ret; 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return ret; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic int acp3x_1015_hw_params(struct snd_pcm_substream *substream, 1318c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = substream->private_data; 1348c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai; 1358c2ecf20Sopenharmony_ci int srate, i, ret; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ret = 0; 1388c2ecf20Sopenharmony_ci srate = params_rate(params); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci for_each_rtd_codec_dais(rtd, i, codec_dai) { 1418c2ecf20Sopenharmony_ci if (strcmp(codec_dai->name, "rt1015-aif")) 1428c2ecf20Sopenharmony_ci continue; 1438c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); 1448c2ecf20Sopenharmony_ci if (ret < 0) 1458c2ecf20Sopenharmony_ci return ret; 1468c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_pll(codec_dai, 0, RT1015_PLL_S_BCLK, 1478c2ecf20Sopenharmony_ci 64 * srate, 256 * srate); 1488c2ecf20Sopenharmony_ci if (ret < 0) 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ci ret = snd_soc_dai_set_sysclk(codec_dai, RT1015_SCLK_S_PLL, 1518c2ecf20Sopenharmony_ci 256 * srate, SND_SOC_CLOCK_IN); 1528c2ecf20Sopenharmony_ci if (ret < 0) 1538c2ecf20Sopenharmony_ci return ret; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci return ret; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void rt5682_clk_disable(void) 1598c2ecf20Sopenharmony_ci{ 1608c2ecf20Sopenharmony_ci clk_disable_unprepare(rt5682_dai_wclk); 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic const unsigned int channels[] = { 1648c2ecf20Sopenharmony_ci DUAL_CHANNEL, 1658c2ecf20Sopenharmony_ci}; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic const unsigned int rates[] = { 1688c2ecf20Sopenharmony_ci 48000, 1698c2ecf20Sopenharmony_ci}; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list constraints_rates = { 1728c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(rates), 1738c2ecf20Sopenharmony_ci .list = rates, 1748c2ecf20Sopenharmony_ci .mask = 0, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list constraints_channels = { 1788c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(channels), 1798c2ecf20Sopenharmony_ci .list = channels, 1808c2ecf20Sopenharmony_ci .mask = 0, 1818c2ecf20Sopenharmony_ci}; 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_cistatic int acp3x_5682_startup(struct snd_pcm_substream *substream) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 1868c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 1878c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 1888c2ecf20Sopenharmony_ci struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci machine->play_i2s_instance = I2S_SP_INSTANCE; 1918c2ecf20Sopenharmony_ci machine->cap_i2s_instance = I2S_SP_INSTANCE; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci runtime->hw.channels_max = DUAL_CHANNEL; 1948c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 1958c2ecf20Sopenharmony_ci &constraints_channels); 1968c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 1978c2ecf20Sopenharmony_ci &constraints_rates); 1988c2ecf20Sopenharmony_ci return rt5682_clk_enable(substream); 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic int acp3x_max_startup(struct snd_pcm_substream *substream) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 2048c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2058c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 2068c2ecf20Sopenharmony_ci struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci machine->play_i2s_instance = I2S_BT_INSTANCE; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci runtime->hw.channels_max = DUAL_CHANNEL; 2118c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2128c2ecf20Sopenharmony_ci &constraints_channels); 2138c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 2148c2ecf20Sopenharmony_ci &constraints_rates); 2158c2ecf20Sopenharmony_ci return rt5682_clk_enable(substream); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int acp3x_ec_dmic0_startup(struct snd_pcm_substream *substream) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2218c2ecf20Sopenharmony_ci struct snd_soc_card *card = rtd->card; 2228c2ecf20Sopenharmony_ci struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 2238c2ecf20Sopenharmony_ci struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci machine->cap_i2s_instance = I2S_BT_INSTANCE; 2268c2ecf20Sopenharmony_ci snd_soc_dai_set_bclk_ratio(codec_dai, 64); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return rt5682_clk_enable(substream); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int dmic_switch; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int dmic_get(struct snd_kcontrol *kcontrol, 2348c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = dmic_switch; 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int dmic_set(struct snd_kcontrol *kcontrol, 2418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci if (dmic_sel) { 2448c2ecf20Sopenharmony_ci dmic_switch = ucontrol->value.integer.value[0]; 2458c2ecf20Sopenharmony_ci gpiod_set_value(dmic_sel, dmic_switch); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void rt5682_shutdown(struct snd_pcm_substream *substream) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci rt5682_clk_disable(); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic const struct snd_soc_ops acp3x_5682_ops = { 2568c2ecf20Sopenharmony_ci .startup = acp3x_5682_startup, 2578c2ecf20Sopenharmony_ci .shutdown = rt5682_shutdown, 2588c2ecf20Sopenharmony_ci}; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic const struct snd_soc_ops acp3x_max_play_ops = { 2618c2ecf20Sopenharmony_ci .startup = acp3x_max_startup, 2628c2ecf20Sopenharmony_ci .shutdown = rt5682_shutdown, 2638c2ecf20Sopenharmony_ci .hw_params = acp3x_1015_hw_params, 2648c2ecf20Sopenharmony_ci}; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_cistatic const struct snd_soc_ops acp3x_ec_cap0_ops = { 2678c2ecf20Sopenharmony_ci .startup = acp3x_ec_dmic0_startup, 2688c2ecf20Sopenharmony_ci .shutdown = rt5682_shutdown, 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(acp3x_i2s, 2728c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.0"))); 2738c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(acp3x_bt, 2748c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.2"))); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(rt5682, 2778c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); 2788c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(max, 2798c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi"))); 2808c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(rt1015, 2818c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC1015:00", "rt1015-aif"), 2828c2ecf20Sopenharmony_ci COMP_CODEC("i2c-10EC1015:01", "rt1015-aif"))); 2838c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(cros_ec, 2848c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_CODEC("GOOG0013:00", "EC Codec I2S RX"))); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciSND_SOC_DAILINK_DEF(platform, 2878c2ecf20Sopenharmony_ci DAILINK_COMP_ARRAY(COMP_PLATFORM("acp3x_rv_i2s_dma.0"))); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic struct snd_soc_codec_conf rt1015_conf[] = { 2908c2ecf20Sopenharmony_ci { 2918c2ecf20Sopenharmony_ci .dlc = COMP_CODEC_CONF("i2c-10EC1015:00"), 2928c2ecf20Sopenharmony_ci .name_prefix = "Left", 2938c2ecf20Sopenharmony_ci }, 2948c2ecf20Sopenharmony_ci { 2958c2ecf20Sopenharmony_ci .dlc = COMP_CODEC_CONF("i2c-10EC1015:01"), 2968c2ecf20Sopenharmony_ci .name_prefix = "Right", 2978c2ecf20Sopenharmony_ci }, 2988c2ecf20Sopenharmony_ci}; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_cistatic struct snd_soc_dai_link acp3x_dai[] = { 3018c2ecf20Sopenharmony_ci [RT5682] = { 3028c2ecf20Sopenharmony_ci .name = "acp3x-5682-play", 3038c2ecf20Sopenharmony_ci .stream_name = "Playback", 3048c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 3058c2ecf20Sopenharmony_ci | SND_SOC_DAIFMT_CBM_CFM, 3068c2ecf20Sopenharmony_ci .init = acp3x_5682_init, 3078c2ecf20Sopenharmony_ci .dpcm_playback = 1, 3088c2ecf20Sopenharmony_ci .dpcm_capture = 1, 3098c2ecf20Sopenharmony_ci .ops = &acp3x_5682_ops, 3108c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform), 3118c2ecf20Sopenharmony_ci }, 3128c2ecf20Sopenharmony_ci [MAX] = { 3138c2ecf20Sopenharmony_ci .name = "acp3x-max98357-play", 3148c2ecf20Sopenharmony_ci .stream_name = "HiFi Playback", 3158c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 3168c2ecf20Sopenharmony_ci | SND_SOC_DAIFMT_CBS_CFS, 3178c2ecf20Sopenharmony_ci .dpcm_playback = 1, 3188c2ecf20Sopenharmony_ci .ops = &acp3x_max_play_ops, 3198c2ecf20Sopenharmony_ci .cpus = acp3x_bt, 3208c2ecf20Sopenharmony_ci .num_cpus = ARRAY_SIZE(acp3x_bt), 3218c2ecf20Sopenharmony_ci .platforms = platform, 3228c2ecf20Sopenharmony_ci .num_platforms = ARRAY_SIZE(platform), 3238c2ecf20Sopenharmony_ci }, 3248c2ecf20Sopenharmony_ci [EC] = { 3258c2ecf20Sopenharmony_ci .name = "acp3x-ec-dmic0-capture", 3268c2ecf20Sopenharmony_ci .stream_name = "Capture DMIC0", 3278c2ecf20Sopenharmony_ci .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 3288c2ecf20Sopenharmony_ci | SND_SOC_DAIFMT_CBS_CFS, 3298c2ecf20Sopenharmony_ci .dpcm_capture = 1, 3308c2ecf20Sopenharmony_ci .ops = &acp3x_ec_cap0_ops, 3318c2ecf20Sopenharmony_ci SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform), 3328c2ecf20Sopenharmony_ci }, 3338c2ecf20Sopenharmony_ci}; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic const char * const dmic_mux_text[] = { 3368c2ecf20Sopenharmony_ci "Front Mic", 3378c2ecf20Sopenharmony_ci "Rear Mic", 3388c2ecf20Sopenharmony_ci}; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL( 3418c2ecf20Sopenharmony_ci acp3x_dmic_enum, SND_SOC_NOPM, 0, dmic_mux_text); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new acp3x_dmic_mux_control = 3448c2ecf20Sopenharmony_ci SOC_DAPM_ENUM_EXT("DMIC Select Mux", acp3x_dmic_enum, 3458c2ecf20Sopenharmony_ci dmic_get, dmic_set); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget acp3x_5682_widgets[] = { 3488c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", NULL), 3498c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Spk", NULL), 3508c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 3518c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, 3528c2ecf20Sopenharmony_ci &acp3x_dmic_mux_control), 3538c2ecf20Sopenharmony_ci}; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route acp3x_5682_audio_route[] = { 3568c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPOL"}, 3578c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPOR"}, 3588c2ecf20Sopenharmony_ci {"IN1P", NULL, "Headset Mic"}, 3598c2ecf20Sopenharmony_ci {"Spk", NULL, "Speaker"}, 3608c2ecf20Sopenharmony_ci {"Dmic Mux", "Front Mic", "DMIC"}, 3618c2ecf20Sopenharmony_ci {"Dmic Mux", "Rear Mic", "DMIC"}, 3628c2ecf20Sopenharmony_ci}; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new acp3x_5682_mc_controls[] = { 3658c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headphone Jack"), 3668c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Spk"), 3678c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 3688c2ecf20Sopenharmony_ci}; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic struct snd_soc_card acp3x_5682 = { 3718c2ecf20Sopenharmony_ci .name = "acp3xalc5682m98357", 3728c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3738c2ecf20Sopenharmony_ci .dai_link = acp3x_dai, 3748c2ecf20Sopenharmony_ci .num_links = ARRAY_SIZE(acp3x_dai), 3758c2ecf20Sopenharmony_ci .dapm_widgets = acp3x_5682_widgets, 3768c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(acp3x_5682_widgets), 3778c2ecf20Sopenharmony_ci .dapm_routes = acp3x_5682_audio_route, 3788c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(acp3x_5682_audio_route), 3798c2ecf20Sopenharmony_ci .controls = acp3x_5682_mc_controls, 3808c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(acp3x_5682_mc_controls), 3818c2ecf20Sopenharmony_ci}; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_widget acp3x_1015_widgets[] = { 3848c2ecf20Sopenharmony_ci SND_SOC_DAPM_HP("Headphone Jack", NULL), 3858c2ecf20Sopenharmony_ci SND_SOC_DAPM_MIC("Headset Mic", NULL), 3868c2ecf20Sopenharmony_ci SND_SOC_DAPM_MUX("Dmic Mux", SND_SOC_NOPM, 0, 0, 3878c2ecf20Sopenharmony_ci &acp3x_dmic_mux_control), 3888c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Left Spk", NULL), 3898c2ecf20Sopenharmony_ci SND_SOC_DAPM_SPK("Right Spk", NULL), 3908c2ecf20Sopenharmony_ci}; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic const struct snd_soc_dapm_route acp3x_1015_route[] = { 3938c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPOL"}, 3948c2ecf20Sopenharmony_ci {"Headphone Jack", NULL, "HPOR"}, 3958c2ecf20Sopenharmony_ci {"IN1P", NULL, "Headset Mic"}, 3968c2ecf20Sopenharmony_ci {"Dmic Mux", "Front Mic", "DMIC"}, 3978c2ecf20Sopenharmony_ci {"Dmic Mux", "Rear Mic", "DMIC"}, 3988c2ecf20Sopenharmony_ci {"Left Spk", NULL, "Left SPO"}, 3998c2ecf20Sopenharmony_ci {"Right Spk", NULL, "Right SPO"}, 4008c2ecf20Sopenharmony_ci}; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new acp3x_mc_1015_controls[] = { 4038c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headphone Jack"), 4048c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Headset Mic"), 4058c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Left Spk"), 4068c2ecf20Sopenharmony_ci SOC_DAPM_PIN_SWITCH("Right Spk"), 4078c2ecf20Sopenharmony_ci}; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic struct snd_soc_card acp3x_1015 = { 4108c2ecf20Sopenharmony_ci .name = "acp3xalc56821015", 4118c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4128c2ecf20Sopenharmony_ci .dai_link = acp3x_dai, 4138c2ecf20Sopenharmony_ci .num_links = ARRAY_SIZE(acp3x_dai), 4148c2ecf20Sopenharmony_ci .dapm_widgets = acp3x_1015_widgets, 4158c2ecf20Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(acp3x_1015_widgets), 4168c2ecf20Sopenharmony_ci .dapm_routes = acp3x_1015_route, 4178c2ecf20Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(acp3x_1015_route), 4188c2ecf20Sopenharmony_ci .codec_conf = rt1015_conf, 4198c2ecf20Sopenharmony_ci .num_configs = ARRAY_SIZE(rt1015_conf), 4208c2ecf20Sopenharmony_ci .controls = acp3x_mc_1015_controls, 4218c2ecf20Sopenharmony_ci .num_controls = ARRAY_SIZE(acp3x_mc_1015_controls), 4228c2ecf20Sopenharmony_ci}; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_civoid *soc_is_rltk_max(struct device *dev) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci const struct acpi_device_id *match; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci match = acpi_match_device(dev->driver->acpi_match_table, dev); 4298c2ecf20Sopenharmony_ci if (!match) 4308c2ecf20Sopenharmony_ci return NULL; 4318c2ecf20Sopenharmony_ci return (void *)match->driver_data; 4328c2ecf20Sopenharmony_ci} 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_cistatic void card_spk_dai_link_present(struct snd_soc_dai_link *links, 4358c2ecf20Sopenharmony_ci const char *card_name) 4368c2ecf20Sopenharmony_ci{ 4378c2ecf20Sopenharmony_ci if (!strcmp(card_name, "acp3xalc56821015")) { 4388c2ecf20Sopenharmony_ci links[1].codecs = rt1015; 4398c2ecf20Sopenharmony_ci links[1].num_codecs = ARRAY_SIZE(rt1015); 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci links[1].codecs = max; 4428c2ecf20Sopenharmony_ci links[1].num_codecs = ARRAY_SIZE(max); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci} 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic int acp3x_probe(struct platform_device *pdev) 4478c2ecf20Sopenharmony_ci{ 4488c2ecf20Sopenharmony_ci int ret; 4498c2ecf20Sopenharmony_ci struct snd_soc_card *card; 4508c2ecf20Sopenharmony_ci struct acp3x_platform_info *machine; 4518c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci card = (struct snd_soc_card *)soc_is_rltk_max(dev); 4548c2ecf20Sopenharmony_ci if (!card) 4558c2ecf20Sopenharmony_ci return -ENODEV; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci machine = devm_kzalloc(&pdev->dev, sizeof(*machine), GFP_KERNEL); 4588c2ecf20Sopenharmony_ci if (!machine) 4598c2ecf20Sopenharmony_ci return -ENOMEM; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci card_spk_dai_link_present(card->dai_link, card->name); 4628c2ecf20Sopenharmony_ci card->dev = &pdev->dev; 4638c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, card); 4648c2ecf20Sopenharmony_ci snd_soc_card_set_drvdata(card, machine); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci dmic_sel = devm_gpiod_get(&pdev->dev, "dmic", GPIOD_OUT_LOW); 4678c2ecf20Sopenharmony_ci if (IS_ERR(dmic_sel)) { 4688c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "DMIC gpio failed err=%ld\n", 4698c2ecf20Sopenharmony_ci PTR_ERR(dmic_sel)); 4708c2ecf20Sopenharmony_ci return PTR_ERR(dmic_sel); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_card(&pdev->dev, card); 4748c2ecf20Sopenharmony_ci if (ret) { 4758c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 4768c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 4778c2ecf20Sopenharmony_ci "devm_snd_soc_register_card(%s) failed: %d\n", 4788c2ecf20Sopenharmony_ci card->name, ret); 4798c2ecf20Sopenharmony_ci else 4808c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, 4818c2ecf20Sopenharmony_ci "devm_snd_soc_register_card(%s) probe deferred: %d\n", 4828c2ecf20Sopenharmony_ci card->name, ret); 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci return ret; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic const struct acpi_device_id acp3x_audio_acpi_match[] = { 4898c2ecf20Sopenharmony_ci { "AMDI5682", (unsigned long)&acp3x_5682}, 4908c2ecf20Sopenharmony_ci { "AMDI1015", (unsigned long)&acp3x_1015}, 4918c2ecf20Sopenharmony_ci {}, 4928c2ecf20Sopenharmony_ci}; 4938c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic struct platform_driver acp3x_audio = { 4968c2ecf20Sopenharmony_ci .driver = { 4978c2ecf20Sopenharmony_ci .name = "acp3x-alc5682-max98357", 4988c2ecf20Sopenharmony_ci .acpi_match_table = ACPI_PTR(acp3x_audio_acpi_match), 4998c2ecf20Sopenharmony_ci .pm = &snd_soc_pm_ops, 5008c2ecf20Sopenharmony_ci }, 5018c2ecf20Sopenharmony_ci .probe = acp3x_probe, 5028c2ecf20Sopenharmony_ci}; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cimodule_platform_driver(acp3x_audio); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciMODULE_AUTHOR("akshu.agrawal@amd.com"); 5078c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vishnuvardhanrao.Ravulapati@amd.com"); 5088c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("ALC5682 ALC1015 & MAX98357 audio support"); 5098c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 510