1*6b8e4e7dSAkshu Agrawal // SPDX-License-Identifier: GPL-2.0+ 2*6b8e4e7dSAkshu Agrawal // 3*6b8e4e7dSAkshu Agrawal // Machine driver for AMD ACP Audio engine using DA7219 & MAX98357 codec. 4*6b8e4e7dSAkshu Agrawal // 5*6b8e4e7dSAkshu Agrawal //Copyright 2016 Advanced Micro Devices, Inc. 6*6b8e4e7dSAkshu Agrawal 7*6b8e4e7dSAkshu Agrawal #include <sound/core.h> 8*6b8e4e7dSAkshu Agrawal #include <sound/soc.h> 9*6b8e4e7dSAkshu Agrawal #include <sound/pcm.h> 10*6b8e4e7dSAkshu Agrawal #include <sound/pcm_params.h> 11*6b8e4e7dSAkshu Agrawal #include <sound/soc-dapm.h> 12*6b8e4e7dSAkshu Agrawal #include <sound/jack.h> 13*6b8e4e7dSAkshu Agrawal #include <linux/clk.h> 14*6b8e4e7dSAkshu Agrawal #include <linux/gpio.h> 15*6b8e4e7dSAkshu Agrawal #include <linux/module.h> 16*6b8e4e7dSAkshu Agrawal #include <linux/i2c.h> 17*6b8e4e7dSAkshu Agrawal #include <linux/input.h> 18*6b8e4e7dSAkshu Agrawal #include <linux/acpi.h> 19*6b8e4e7dSAkshu Agrawal 20*6b8e4e7dSAkshu Agrawal #include "raven/acp3x.h" 21*6b8e4e7dSAkshu Agrawal #include "../codecs/rt5682.h" 22*6b8e4e7dSAkshu Agrawal 23*6b8e4e7dSAkshu Agrawal #define PCO_PLAT_CLK 48000000 24*6b8e4e7dSAkshu Agrawal #define RT5682_PLL_FREQ (48000 * 512) 25*6b8e4e7dSAkshu Agrawal #define DUAL_CHANNEL 2 26*6b8e4e7dSAkshu Agrawal 27*6b8e4e7dSAkshu Agrawal static struct snd_soc_jack pco_jack; 28*6b8e4e7dSAkshu Agrawal static struct clk *rt5682_dai_wclk; 29*6b8e4e7dSAkshu Agrawal static struct clk *rt5682_dai_bclk; 30*6b8e4e7dSAkshu Agrawal 31*6b8e4e7dSAkshu Agrawal static int acp3x_5682_init(struct snd_soc_pcm_runtime *rtd) 32*6b8e4e7dSAkshu Agrawal { 33*6b8e4e7dSAkshu Agrawal int ret; 34*6b8e4e7dSAkshu Agrawal struct snd_soc_card *card = rtd->card; 35*6b8e4e7dSAkshu Agrawal struct snd_soc_dai *codec_dai = rtd->codec_dai; 36*6b8e4e7dSAkshu Agrawal struct snd_soc_component *component = codec_dai->component; 37*6b8e4e7dSAkshu Agrawal 38*6b8e4e7dSAkshu Agrawal dev_info(rtd->dev, "codec dai name = %s\n", codec_dai->name); 39*6b8e4e7dSAkshu Agrawal 40*6b8e4e7dSAkshu Agrawal /* set rt5682 dai fmt */ 41*6b8e4e7dSAkshu Agrawal ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S 42*6b8e4e7dSAkshu Agrawal | SND_SOC_DAIFMT_NB_NF 43*6b8e4e7dSAkshu Agrawal | SND_SOC_DAIFMT_CBM_CFM); 44*6b8e4e7dSAkshu Agrawal if (ret < 0) { 45*6b8e4e7dSAkshu Agrawal dev_err(rtd->card->dev, 46*6b8e4e7dSAkshu Agrawal "Failed to set rt5682 dai fmt: %d\n", ret); 47*6b8e4e7dSAkshu Agrawal return ret; 48*6b8e4e7dSAkshu Agrawal } 49*6b8e4e7dSAkshu Agrawal 50*6b8e4e7dSAkshu Agrawal /* set codec PLL */ 51*6b8e4e7dSAkshu Agrawal ret = snd_soc_dai_set_pll(codec_dai, RT5682_PLL2, RT5682_PLL2_S_MCLK, 52*6b8e4e7dSAkshu Agrawal PCO_PLAT_CLK, RT5682_PLL_FREQ); 53*6b8e4e7dSAkshu Agrawal if (ret < 0) { 54*6b8e4e7dSAkshu Agrawal dev_err(rtd->dev, "can't set rt5682 PLL: %d\n", ret); 55*6b8e4e7dSAkshu Agrawal return ret; 56*6b8e4e7dSAkshu Agrawal } 57*6b8e4e7dSAkshu Agrawal 58*6b8e4e7dSAkshu Agrawal /* Set codec sysclk */ 59*6b8e4e7dSAkshu Agrawal ret = snd_soc_dai_set_sysclk(codec_dai, RT5682_SCLK_S_PLL2, 60*6b8e4e7dSAkshu Agrawal RT5682_PLL_FREQ, SND_SOC_CLOCK_IN); 61*6b8e4e7dSAkshu Agrawal if (ret < 0) { 62*6b8e4e7dSAkshu Agrawal dev_err(rtd->dev, 63*6b8e4e7dSAkshu Agrawal "Failed to set rt5682 SYSCLK: %d\n", ret); 64*6b8e4e7dSAkshu Agrawal return ret; 65*6b8e4e7dSAkshu Agrawal } 66*6b8e4e7dSAkshu Agrawal 67*6b8e4e7dSAkshu Agrawal /* Set tdm/i2s1 master bclk ratio */ 68*6b8e4e7dSAkshu Agrawal ret = snd_soc_dai_set_bclk_ratio(codec_dai, 64); 69*6b8e4e7dSAkshu Agrawal if (ret < 0) { 70*6b8e4e7dSAkshu Agrawal dev_err(rtd->dev, 71*6b8e4e7dSAkshu Agrawal "Failed to set rt5682 tdm bclk ratio: %d\n", ret); 72*6b8e4e7dSAkshu Agrawal return ret; 73*6b8e4e7dSAkshu Agrawal } 74*6b8e4e7dSAkshu Agrawal 75*6b8e4e7dSAkshu Agrawal rt5682_dai_wclk = clk_get(component->dev, "rt5682-dai-wclk"); 76*6b8e4e7dSAkshu Agrawal rt5682_dai_bclk = clk_get(component->dev, "rt5682-dai-bclk"); 77*6b8e4e7dSAkshu Agrawal 78*6b8e4e7dSAkshu Agrawal ret = snd_soc_card_jack_new(card, "Headset Jack", 79*6b8e4e7dSAkshu Agrawal SND_JACK_HEADSET | SND_JACK_LINEOUT | 80*6b8e4e7dSAkshu Agrawal SND_JACK_BTN_0 | SND_JACK_BTN_1 | 81*6b8e4e7dSAkshu Agrawal SND_JACK_BTN_2 | SND_JACK_BTN_3, 82*6b8e4e7dSAkshu Agrawal &pco_jack, NULL, 0); 83*6b8e4e7dSAkshu Agrawal if (ret) { 84*6b8e4e7dSAkshu Agrawal dev_err(card->dev, "HP jack creation failed %d\n", ret); 85*6b8e4e7dSAkshu Agrawal return ret; 86*6b8e4e7dSAkshu Agrawal } 87*6b8e4e7dSAkshu Agrawal 88*6b8e4e7dSAkshu Agrawal snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 89*6b8e4e7dSAkshu Agrawal snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP); 90*6b8e4e7dSAkshu Agrawal snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); 91*6b8e4e7dSAkshu Agrawal snd_jack_set_key(pco_jack.jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); 92*6b8e4e7dSAkshu Agrawal 93*6b8e4e7dSAkshu Agrawal ret = snd_soc_component_set_jack(component, &pco_jack, NULL); 94*6b8e4e7dSAkshu Agrawal if (ret) { 95*6b8e4e7dSAkshu Agrawal dev_err(rtd->dev, "Headset Jack call-back failed: %d\n", ret); 96*6b8e4e7dSAkshu Agrawal return ret; 97*6b8e4e7dSAkshu Agrawal } 98*6b8e4e7dSAkshu Agrawal 99*6b8e4e7dSAkshu Agrawal return ret; 100*6b8e4e7dSAkshu Agrawal } 101*6b8e4e7dSAkshu Agrawal 102*6b8e4e7dSAkshu Agrawal static int rt5682_clk_enable(struct snd_pcm_substream *substream) 103*6b8e4e7dSAkshu Agrawal { 104*6b8e4e7dSAkshu Agrawal int ret = 0; 105*6b8e4e7dSAkshu Agrawal struct snd_soc_pcm_runtime *rtd = substream->private_data; 106*6b8e4e7dSAkshu Agrawal 107*6b8e4e7dSAkshu Agrawal /* RT5682 will support only 48K output with 48M mclk */ 108*6b8e4e7dSAkshu Agrawal clk_set_rate(rt5682_dai_wclk, 48000); 109*6b8e4e7dSAkshu Agrawal clk_set_rate(rt5682_dai_bclk, 48000 * 64); 110*6b8e4e7dSAkshu Agrawal ret = clk_prepare_enable(rt5682_dai_wclk); 111*6b8e4e7dSAkshu Agrawal if (ret < 0) { 112*6b8e4e7dSAkshu Agrawal dev_err(rtd->dev, "can't enable wclk %d\n", ret); 113*6b8e4e7dSAkshu Agrawal return ret; 114*6b8e4e7dSAkshu Agrawal } 115*6b8e4e7dSAkshu Agrawal 116*6b8e4e7dSAkshu Agrawal return ret; 117*6b8e4e7dSAkshu Agrawal } 118*6b8e4e7dSAkshu Agrawal 119*6b8e4e7dSAkshu Agrawal static void rt5682_clk_disable(void) 120*6b8e4e7dSAkshu Agrawal { 121*6b8e4e7dSAkshu Agrawal clk_disable_unprepare(rt5682_dai_wclk); 122*6b8e4e7dSAkshu Agrawal } 123*6b8e4e7dSAkshu Agrawal 124*6b8e4e7dSAkshu Agrawal static const unsigned int channels[] = { 125*6b8e4e7dSAkshu Agrawal DUAL_CHANNEL, 126*6b8e4e7dSAkshu Agrawal }; 127*6b8e4e7dSAkshu Agrawal 128*6b8e4e7dSAkshu Agrawal static const unsigned int rates[] = { 129*6b8e4e7dSAkshu Agrawal 48000, 130*6b8e4e7dSAkshu Agrawal }; 131*6b8e4e7dSAkshu Agrawal 132*6b8e4e7dSAkshu Agrawal static const struct snd_pcm_hw_constraint_list constraints_rates = { 133*6b8e4e7dSAkshu Agrawal .count = ARRAY_SIZE(rates), 134*6b8e4e7dSAkshu Agrawal .list = rates, 135*6b8e4e7dSAkshu Agrawal .mask = 0, 136*6b8e4e7dSAkshu Agrawal }; 137*6b8e4e7dSAkshu Agrawal 138*6b8e4e7dSAkshu Agrawal static const struct snd_pcm_hw_constraint_list constraints_channels = { 139*6b8e4e7dSAkshu Agrawal .count = ARRAY_SIZE(channels), 140*6b8e4e7dSAkshu Agrawal .list = channels, 141*6b8e4e7dSAkshu Agrawal .mask = 0, 142*6b8e4e7dSAkshu Agrawal }; 143*6b8e4e7dSAkshu Agrawal 144*6b8e4e7dSAkshu Agrawal static int acp3x_5682_startup(struct snd_pcm_substream *substream) 145*6b8e4e7dSAkshu Agrawal { 146*6b8e4e7dSAkshu Agrawal struct snd_pcm_runtime *runtime = substream->runtime; 147*6b8e4e7dSAkshu Agrawal struct snd_soc_pcm_runtime *rtd = substream->private_data; 148*6b8e4e7dSAkshu Agrawal struct snd_soc_card *card = rtd->card; 149*6b8e4e7dSAkshu Agrawal struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); 150*6b8e4e7dSAkshu Agrawal 151*6b8e4e7dSAkshu Agrawal machine->play_i2s_instance = I2S_SP_INSTANCE; 152*6b8e4e7dSAkshu Agrawal machine->cap_i2s_instance = I2S_SP_INSTANCE; 153*6b8e4e7dSAkshu Agrawal 154*6b8e4e7dSAkshu Agrawal runtime->hw.channels_max = DUAL_CHANNEL; 155*6b8e4e7dSAkshu Agrawal snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 156*6b8e4e7dSAkshu Agrawal &constraints_channels); 157*6b8e4e7dSAkshu Agrawal snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 158*6b8e4e7dSAkshu Agrawal &constraints_rates); 159*6b8e4e7dSAkshu Agrawal return rt5682_clk_enable(substream); 160*6b8e4e7dSAkshu Agrawal } 161*6b8e4e7dSAkshu Agrawal 162*6b8e4e7dSAkshu Agrawal static int acp3x_max_startup(struct snd_pcm_substream *substream) 163*6b8e4e7dSAkshu Agrawal { 164*6b8e4e7dSAkshu Agrawal struct snd_pcm_runtime *runtime = substream->runtime; 165*6b8e4e7dSAkshu Agrawal struct snd_soc_pcm_runtime *rtd = substream->private_data; 166*6b8e4e7dSAkshu Agrawal struct snd_soc_card *card = rtd->card; 167*6b8e4e7dSAkshu Agrawal struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); 168*6b8e4e7dSAkshu Agrawal 169*6b8e4e7dSAkshu Agrawal machine->play_i2s_instance = I2S_BT_INSTANCE; 170*6b8e4e7dSAkshu Agrawal 171*6b8e4e7dSAkshu Agrawal runtime->hw.channels_max = DUAL_CHANNEL; 172*6b8e4e7dSAkshu Agrawal snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 173*6b8e4e7dSAkshu Agrawal &constraints_channels); 174*6b8e4e7dSAkshu Agrawal snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 175*6b8e4e7dSAkshu Agrawal &constraints_rates); 176*6b8e4e7dSAkshu Agrawal return rt5682_clk_enable(substream); 177*6b8e4e7dSAkshu Agrawal } 178*6b8e4e7dSAkshu Agrawal 179*6b8e4e7dSAkshu Agrawal static int acp3x_ec_startup(struct snd_pcm_substream *substream) 180*6b8e4e7dSAkshu Agrawal { 181*6b8e4e7dSAkshu Agrawal struct snd_soc_pcm_runtime *rtd = substream->private_data; 182*6b8e4e7dSAkshu Agrawal struct snd_soc_card *card = rtd->card; 183*6b8e4e7dSAkshu Agrawal struct snd_soc_dai *codec_dai = rtd->codec_dai; 184*6b8e4e7dSAkshu Agrawal struct acp3x_platform_info *machine = snd_soc_card_get_drvdata(card); 185*6b8e4e7dSAkshu Agrawal 186*6b8e4e7dSAkshu Agrawal machine->cap_i2s_instance = I2S_BT_INSTANCE; 187*6b8e4e7dSAkshu Agrawal snd_soc_dai_set_bclk_ratio(codec_dai, 64); 188*6b8e4e7dSAkshu Agrawal 189*6b8e4e7dSAkshu Agrawal return rt5682_clk_enable(substream); 190*6b8e4e7dSAkshu Agrawal } 191*6b8e4e7dSAkshu Agrawal 192*6b8e4e7dSAkshu Agrawal static void rt5682_shutdown(struct snd_pcm_substream *substream) 193*6b8e4e7dSAkshu Agrawal { 194*6b8e4e7dSAkshu Agrawal rt5682_clk_disable(); 195*6b8e4e7dSAkshu Agrawal } 196*6b8e4e7dSAkshu Agrawal 197*6b8e4e7dSAkshu Agrawal static const struct snd_soc_ops acp3x_5682_ops = { 198*6b8e4e7dSAkshu Agrawal .startup = acp3x_5682_startup, 199*6b8e4e7dSAkshu Agrawal .shutdown = rt5682_shutdown, 200*6b8e4e7dSAkshu Agrawal }; 201*6b8e4e7dSAkshu Agrawal 202*6b8e4e7dSAkshu Agrawal static const struct snd_soc_ops acp3x_max_play_ops = { 203*6b8e4e7dSAkshu Agrawal .startup = acp3x_max_startup, 204*6b8e4e7dSAkshu Agrawal .shutdown = rt5682_shutdown, 205*6b8e4e7dSAkshu Agrawal }; 206*6b8e4e7dSAkshu Agrawal 207*6b8e4e7dSAkshu Agrawal static const struct snd_soc_ops acp3x_ec_cap_ops = { 208*6b8e4e7dSAkshu Agrawal .startup = acp3x_ec_startup, 209*6b8e4e7dSAkshu Agrawal .shutdown = rt5682_shutdown, 210*6b8e4e7dSAkshu Agrawal }; 211*6b8e4e7dSAkshu Agrawal 212*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_DEF(acp3x_i2s, 213*6b8e4e7dSAkshu Agrawal DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.0"))); 214*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_DEF(acp3x_bt, 215*6b8e4e7dSAkshu Agrawal DAILINK_COMP_ARRAY(COMP_CPU("acp3x_i2s_playcap.2"))); 216*6b8e4e7dSAkshu Agrawal 217*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_DEF(rt5682, 218*6b8e4e7dSAkshu Agrawal DAILINK_COMP_ARRAY(COMP_CODEC("i2c-10EC5682:00", "rt5682-aif1"))); 219*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_DEF(max, 220*6b8e4e7dSAkshu Agrawal DAILINK_COMP_ARRAY(COMP_CODEC("MX98357A:00", "HiFi"))); 221*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_DEF(cros_ec, 222*6b8e4e7dSAkshu Agrawal DAILINK_COMP_ARRAY(COMP_CODEC("GOOG0013:00", "EC Codec I2S RX"))); 223*6b8e4e7dSAkshu Agrawal 224*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_DEF(platform, 225*6b8e4e7dSAkshu Agrawal DAILINK_COMP_ARRAY(COMP_PLATFORM("acp3x_rv_i2s_dma.0"))); 226*6b8e4e7dSAkshu Agrawal 227*6b8e4e7dSAkshu Agrawal static struct snd_soc_dai_link acp3x_dai_5682_98357[] = { 228*6b8e4e7dSAkshu Agrawal { 229*6b8e4e7dSAkshu Agrawal .name = "acp3x-5682-play", 230*6b8e4e7dSAkshu Agrawal .stream_name = "Playback", 231*6b8e4e7dSAkshu Agrawal .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 232*6b8e4e7dSAkshu Agrawal | SND_SOC_DAIFMT_CBM_CFM, 233*6b8e4e7dSAkshu Agrawal .init = acp3x_5682_init, 234*6b8e4e7dSAkshu Agrawal .dpcm_playback = 1, 235*6b8e4e7dSAkshu Agrawal .dpcm_capture = 1, 236*6b8e4e7dSAkshu Agrawal .ops = &acp3x_5682_ops, 237*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_REG(acp3x_i2s, rt5682, platform), 238*6b8e4e7dSAkshu Agrawal }, 239*6b8e4e7dSAkshu Agrawal { 240*6b8e4e7dSAkshu Agrawal .name = "acp3x-max98357-play", 241*6b8e4e7dSAkshu Agrawal .stream_name = "HiFi Playback", 242*6b8e4e7dSAkshu Agrawal .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 243*6b8e4e7dSAkshu Agrawal | SND_SOC_DAIFMT_CBM_CFM, 244*6b8e4e7dSAkshu Agrawal .dpcm_playback = 1, 245*6b8e4e7dSAkshu Agrawal .ops = &acp3x_max_play_ops, 246*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_REG(acp3x_bt, max, platform), 247*6b8e4e7dSAkshu Agrawal }, 248*6b8e4e7dSAkshu Agrawal { 249*6b8e4e7dSAkshu Agrawal .name = "acp3x-ec-capture", 250*6b8e4e7dSAkshu Agrawal .stream_name = "Capture", 251*6b8e4e7dSAkshu Agrawal .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 252*6b8e4e7dSAkshu Agrawal | SND_SOC_DAIFMT_CBS_CFS, 253*6b8e4e7dSAkshu Agrawal .dpcm_capture = 1, 254*6b8e4e7dSAkshu Agrawal .ops = &acp3x_ec_cap_ops, 255*6b8e4e7dSAkshu Agrawal SND_SOC_DAILINK_REG(acp3x_bt, cros_ec, platform), 256*6b8e4e7dSAkshu Agrawal }, 257*6b8e4e7dSAkshu Agrawal }; 258*6b8e4e7dSAkshu Agrawal 259*6b8e4e7dSAkshu Agrawal static const struct snd_soc_dapm_widget acp3x_widgets[] = { 260*6b8e4e7dSAkshu Agrawal SND_SOC_DAPM_HP("Headphone Jack", NULL), 261*6b8e4e7dSAkshu Agrawal SND_SOC_DAPM_SPK("Spk", NULL), 262*6b8e4e7dSAkshu Agrawal SND_SOC_DAPM_MIC("Headset Mic", NULL), 263*6b8e4e7dSAkshu Agrawal }; 264*6b8e4e7dSAkshu Agrawal 265*6b8e4e7dSAkshu Agrawal static const struct snd_soc_dapm_route acp3x_audio_route[] = { 266*6b8e4e7dSAkshu Agrawal {"Headphone Jack", NULL, "HPOL"}, 267*6b8e4e7dSAkshu Agrawal {"Headphone Jack", NULL, "HPOR"}, 268*6b8e4e7dSAkshu Agrawal {"IN1P", NULL, "Headset Mic"}, 269*6b8e4e7dSAkshu Agrawal {"Spk", NULL, "Speaker"}, 270*6b8e4e7dSAkshu Agrawal }; 271*6b8e4e7dSAkshu Agrawal 272*6b8e4e7dSAkshu Agrawal static const struct snd_kcontrol_new acp3x_mc_controls[] = { 273*6b8e4e7dSAkshu Agrawal SOC_DAPM_PIN_SWITCH("Headphone Jack"), 274*6b8e4e7dSAkshu Agrawal SOC_DAPM_PIN_SWITCH("Spk"), 275*6b8e4e7dSAkshu Agrawal SOC_DAPM_PIN_SWITCH("Headset Mic"), 276*6b8e4e7dSAkshu Agrawal }; 277*6b8e4e7dSAkshu Agrawal 278*6b8e4e7dSAkshu Agrawal static struct snd_soc_card acp3x_card = { 279*6b8e4e7dSAkshu Agrawal .name = "acp3xalc5682m98357", 280*6b8e4e7dSAkshu Agrawal .owner = THIS_MODULE, 281*6b8e4e7dSAkshu Agrawal .dai_link = acp3x_dai_5682_98357, 282*6b8e4e7dSAkshu Agrawal .num_links = ARRAY_SIZE(acp3x_dai_5682_98357), 283*6b8e4e7dSAkshu Agrawal .dapm_widgets = acp3x_widgets, 284*6b8e4e7dSAkshu Agrawal .num_dapm_widgets = ARRAY_SIZE(acp3x_widgets), 285*6b8e4e7dSAkshu Agrawal .dapm_routes = acp3x_audio_route, 286*6b8e4e7dSAkshu Agrawal .num_dapm_routes = ARRAY_SIZE(acp3x_audio_route), 287*6b8e4e7dSAkshu Agrawal .controls = acp3x_mc_controls, 288*6b8e4e7dSAkshu Agrawal .num_controls = ARRAY_SIZE(acp3x_mc_controls), 289*6b8e4e7dSAkshu Agrawal }; 290*6b8e4e7dSAkshu Agrawal 291*6b8e4e7dSAkshu Agrawal static int acp3x_probe(struct platform_device *pdev) 292*6b8e4e7dSAkshu Agrawal { 293*6b8e4e7dSAkshu Agrawal int ret; 294*6b8e4e7dSAkshu Agrawal struct snd_soc_card *card; 295*6b8e4e7dSAkshu Agrawal struct acp3x_platform_info *machine; 296*6b8e4e7dSAkshu Agrawal 297*6b8e4e7dSAkshu Agrawal machine = devm_kzalloc(&pdev->dev, sizeof(*machine), GFP_KERNEL); 298*6b8e4e7dSAkshu Agrawal if (!machine) 299*6b8e4e7dSAkshu Agrawal return -ENOMEM; 300*6b8e4e7dSAkshu Agrawal 301*6b8e4e7dSAkshu Agrawal card = &acp3x_card; 302*6b8e4e7dSAkshu Agrawal acp3x_card.dev = &pdev->dev; 303*6b8e4e7dSAkshu Agrawal platform_set_drvdata(pdev, card); 304*6b8e4e7dSAkshu Agrawal snd_soc_card_set_drvdata(card, machine); 305*6b8e4e7dSAkshu Agrawal ret = devm_snd_soc_register_card(&pdev->dev, &acp3x_card); 306*6b8e4e7dSAkshu Agrawal if (ret) { 307*6b8e4e7dSAkshu Agrawal dev_err(&pdev->dev, 308*6b8e4e7dSAkshu Agrawal "devm_snd_soc_register_card(%s) failed: %d\n", 309*6b8e4e7dSAkshu Agrawal acp3x_card.name, ret); 310*6b8e4e7dSAkshu Agrawal return ret; 311*6b8e4e7dSAkshu Agrawal } 312*6b8e4e7dSAkshu Agrawal return 0; 313*6b8e4e7dSAkshu Agrawal } 314*6b8e4e7dSAkshu Agrawal 315*6b8e4e7dSAkshu Agrawal static const struct acpi_device_id acp3x_audio_acpi_match[] = { 316*6b8e4e7dSAkshu Agrawal { "AMDI5682", 0 }, 317*6b8e4e7dSAkshu Agrawal {}, 318*6b8e4e7dSAkshu Agrawal }; 319*6b8e4e7dSAkshu Agrawal MODULE_DEVICE_TABLE(acpi, acp3x_audio_acpi_match); 320*6b8e4e7dSAkshu Agrawal 321*6b8e4e7dSAkshu Agrawal static struct platform_driver acp3x_audio = { 322*6b8e4e7dSAkshu Agrawal .driver = { 323*6b8e4e7dSAkshu Agrawal .name = "acp3x-alc5682-max98357", 324*6b8e4e7dSAkshu Agrawal .acpi_match_table = ACPI_PTR(acp3x_audio_acpi_match), 325*6b8e4e7dSAkshu Agrawal .pm = &snd_soc_pm_ops, 326*6b8e4e7dSAkshu Agrawal }, 327*6b8e4e7dSAkshu Agrawal .probe = acp3x_probe, 328*6b8e4e7dSAkshu Agrawal }; 329*6b8e4e7dSAkshu Agrawal 330*6b8e4e7dSAkshu Agrawal module_platform_driver(acp3x_audio); 331*6b8e4e7dSAkshu Agrawal 332*6b8e4e7dSAkshu Agrawal MODULE_AUTHOR("akshu.agrawal@amd.com"); 333*6b8e4e7dSAkshu Agrawal MODULE_DESCRIPTION("ALC5682 & MAX98357 audio support"); 334*6b8e4e7dSAkshu Agrawal MODULE_LICENSE("GPL v2"); 335