1*34a0094bSVijendar Mukunda // SPDX-License-Identifier: GPL-2.0+ 2*34a0094bSVijendar Mukunda /* 3*34a0094bSVijendar Mukunda * Machine driver for AMD Vangogh platform using NAU8821 & CS35L41 4*34a0094bSVijendar Mukunda * codecs. 5*34a0094bSVijendar Mukunda * 6*34a0094bSVijendar Mukunda * Copyright 2021 Advanced Micro Devices, Inc. 7*34a0094bSVijendar Mukunda */ 8*34a0094bSVijendar Mukunda 9*34a0094bSVijendar Mukunda #include <sound/soc.h> 10*34a0094bSVijendar Mukunda #include <sound/soc-dapm.h> 11*34a0094bSVijendar Mukunda #include <linux/module.h> 12*34a0094bSVijendar Mukunda #include <linux/io.h> 13*34a0094bSVijendar Mukunda #include <sound/pcm.h> 14*34a0094bSVijendar Mukunda #include <sound/pcm_params.h> 15*34a0094bSVijendar Mukunda 16*34a0094bSVijendar Mukunda #include <sound/jack.h> 17*34a0094bSVijendar Mukunda #include <linux/clk.h> 18*34a0094bSVijendar Mukunda #include <linux/gpio.h> 19*34a0094bSVijendar Mukunda #include <linux/gpio/consumer.h> 20*34a0094bSVijendar Mukunda #include <linux/module.h> 21*34a0094bSVijendar Mukunda #include <linux/i2c.h> 22*34a0094bSVijendar Mukunda #include <linux/input.h> 23*34a0094bSVijendar Mukunda #include <linux/io.h> 24*34a0094bSVijendar Mukunda #include <linux/acpi.h> 25*34a0094bSVijendar Mukunda #include <linux/dmi.h> 26*34a0094bSVijendar Mukunda 27*34a0094bSVijendar Mukunda #include "../../codecs/nau8821.h" 28*34a0094bSVijendar Mukunda #include "../../codecs/cs35l41.h" 29*34a0094bSVijendar Mukunda 30*34a0094bSVijendar Mukunda #include "acp5x.h" 31*34a0094bSVijendar Mukunda 32*34a0094bSVijendar Mukunda #define DRV_NAME "acp5x_mach" 33*34a0094bSVijendar Mukunda #define DUAL_CHANNEL 2 34*34a0094bSVijendar Mukunda #define ACP5X_NUVOTON_CODEC_DAI "nau8821-hifi" 35*34a0094bSVijendar Mukunda #define VG_JUPITER 1 36*34a0094bSVijendar Mukunda 37*34a0094bSVijendar Mukunda static unsigned long acp5x_machine_id; 38*34a0094bSVijendar Mukunda static struct snd_soc_jack vg_headset; 39*34a0094bSVijendar Mukunda 40*34a0094bSVijendar Mukunda static struct snd_soc_jack_pin acp5x_nau8821_jack_pins[] = { 41*34a0094bSVijendar Mukunda { 42*34a0094bSVijendar Mukunda .pin = "Headphone", 43*34a0094bSVijendar Mukunda .mask = SND_JACK_HEADPHONE, 44*34a0094bSVijendar Mukunda }, 45*34a0094bSVijendar Mukunda { 46*34a0094bSVijendar Mukunda .pin = "Headset Mic", 47*34a0094bSVijendar Mukunda .mask = SND_JACK_MICROPHONE, 48*34a0094bSVijendar Mukunda }, 49*34a0094bSVijendar Mukunda }; 50*34a0094bSVijendar Mukunda 51*34a0094bSVijendar Mukunda static int acp5x_8821_init(struct snd_soc_pcm_runtime *rtd) 52*34a0094bSVijendar Mukunda { 53*34a0094bSVijendar Mukunda int ret; 54*34a0094bSVijendar Mukunda struct snd_soc_card *card = rtd->card; 55*34a0094bSVijendar Mukunda struct snd_soc_component *component = 56*34a0094bSVijendar Mukunda asoc_rtd_to_codec(rtd, 0)->component; 57*34a0094bSVijendar Mukunda 58*34a0094bSVijendar Mukunda /* 59*34a0094bSVijendar Mukunda * Headset buttons map to the google Reference headset. 60*34a0094bSVijendar Mukunda * These can be configured by userspace. 61*34a0094bSVijendar Mukunda */ 62*34a0094bSVijendar Mukunda ret = snd_soc_card_jack_new(card, "Headset Jack", 63*34a0094bSVijendar Mukunda SND_JACK_HEADSET | SND_JACK_BTN_0, 64*34a0094bSVijendar Mukunda &vg_headset, acp5x_nau8821_jack_pins, 65*34a0094bSVijendar Mukunda ARRAY_SIZE(acp5x_nau8821_jack_pins)); 66*34a0094bSVijendar Mukunda if (ret) { 67*34a0094bSVijendar Mukunda dev_err(rtd->dev, "Headset Jack creation failed %d\n", ret); 68*34a0094bSVijendar Mukunda return ret; 69*34a0094bSVijendar Mukunda } 70*34a0094bSVijendar Mukunda 71*34a0094bSVijendar Mukunda snd_jack_set_key(vg_headset.jack, SND_JACK_BTN_0, KEY_MEDIA); 72*34a0094bSVijendar Mukunda nau8821_enable_jack_detect(component, &vg_headset); 73*34a0094bSVijendar Mukunda return ret; 74*34a0094bSVijendar Mukunda } 75*34a0094bSVijendar Mukunda 76*34a0094bSVijendar Mukunda static int acp5x_cs35l41_init(struct snd_soc_pcm_runtime *rtd) 77*34a0094bSVijendar Mukunda { 78*34a0094bSVijendar Mukunda return 0; 79*34a0094bSVijendar Mukunda } 80*34a0094bSVijendar Mukunda 81*34a0094bSVijendar Mukunda static const unsigned int rates[] = { 82*34a0094bSVijendar Mukunda 48000, 83*34a0094bSVijendar Mukunda }; 84*34a0094bSVijendar Mukunda 85*34a0094bSVijendar Mukunda static const struct snd_pcm_hw_constraint_list constraints_rates = { 86*34a0094bSVijendar Mukunda .count = ARRAY_SIZE(rates), 87*34a0094bSVijendar Mukunda .list = rates, 88*34a0094bSVijendar Mukunda .mask = 0, 89*34a0094bSVijendar Mukunda }; 90*34a0094bSVijendar Mukunda 91*34a0094bSVijendar Mukunda static const unsigned int channels[] = { 92*34a0094bSVijendar Mukunda 2, 93*34a0094bSVijendar Mukunda }; 94*34a0094bSVijendar Mukunda 95*34a0094bSVijendar Mukunda static const struct snd_pcm_hw_constraint_list constraints_channels = { 96*34a0094bSVijendar Mukunda .count = ARRAY_SIZE(channels), 97*34a0094bSVijendar Mukunda .list = channels, 98*34a0094bSVijendar Mukunda .mask = 0, 99*34a0094bSVijendar Mukunda }; 100*34a0094bSVijendar Mukunda 101*34a0094bSVijendar Mukunda static int acp5x_8821_startup(struct snd_pcm_substream *substream) 102*34a0094bSVijendar Mukunda { 103*34a0094bSVijendar Mukunda struct snd_pcm_runtime *runtime = substream->runtime; 104*34a0094bSVijendar Mukunda struct snd_soc_pcm_runtime *rtd = substream->private_data; 105*34a0094bSVijendar Mukunda struct snd_soc_card *card = rtd->card; 106*34a0094bSVijendar Mukunda struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card); 107*34a0094bSVijendar Mukunda 108*34a0094bSVijendar Mukunda machine->play_i2s_instance = I2S_SP_INSTANCE; 109*34a0094bSVijendar Mukunda machine->cap_i2s_instance = I2S_SP_INSTANCE; 110*34a0094bSVijendar Mukunda 111*34a0094bSVijendar Mukunda runtime->hw.channels_max = DUAL_CHANNEL; 112*34a0094bSVijendar Mukunda snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 113*34a0094bSVijendar Mukunda &constraints_channels); 114*34a0094bSVijendar Mukunda snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 115*34a0094bSVijendar Mukunda &constraints_rates); 116*34a0094bSVijendar Mukunda return 0; 117*34a0094bSVijendar Mukunda } 118*34a0094bSVijendar Mukunda 119*34a0094bSVijendar Mukunda static int acp5x_nau8821_hw_params(struct snd_pcm_substream *substream, 120*34a0094bSVijendar Mukunda struct snd_pcm_hw_params *params) 121*34a0094bSVijendar Mukunda { 122*34a0094bSVijendar Mukunda struct snd_soc_pcm_runtime *rtd = substream->private_data; 123*34a0094bSVijendar Mukunda struct snd_soc_card *card = rtd->card; 124*34a0094bSVijendar Mukunda struct snd_soc_dai *codec_dai = 125*34a0094bSVijendar Mukunda snd_soc_card_get_codec_dai(card, 126*34a0094bSVijendar Mukunda ACP5X_NUVOTON_CODEC_DAI); 127*34a0094bSVijendar Mukunda int ret; 128*34a0094bSVijendar Mukunda 129*34a0094bSVijendar Mukunda ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_FLL_BLK, 0, 130*34a0094bSVijendar Mukunda SND_SOC_CLOCK_IN); 131*34a0094bSVijendar Mukunda if (ret < 0) 132*34a0094bSVijendar Mukunda dev_err(card->dev, "can't set FS clock %d\n", ret); 133*34a0094bSVijendar Mukunda ret = snd_soc_dai_set_pll(codec_dai, 0, 0, snd_soc_params_to_bclk(params), 134*34a0094bSVijendar Mukunda params_rate(params) * 256); 135*34a0094bSVijendar Mukunda if (ret < 0) 136*34a0094bSVijendar Mukunda dev_err(card->dev, "can't set FLL: %d\n", ret); 137*34a0094bSVijendar Mukunda 138*34a0094bSVijendar Mukunda return ret; 139*34a0094bSVijendar Mukunda } 140*34a0094bSVijendar Mukunda 141*34a0094bSVijendar Mukunda static int acp5x_cs35l41_startup(struct snd_pcm_substream *substream) 142*34a0094bSVijendar Mukunda { 143*34a0094bSVijendar Mukunda struct snd_pcm_runtime *runtime = substream->runtime; 144*34a0094bSVijendar Mukunda struct snd_soc_pcm_runtime *rtd = substream->private_data; 145*34a0094bSVijendar Mukunda struct snd_soc_card *card = rtd->card; 146*34a0094bSVijendar Mukunda struct acp5x_platform_info *machine = snd_soc_card_get_drvdata(card); 147*34a0094bSVijendar Mukunda 148*34a0094bSVijendar Mukunda machine->play_i2s_instance = I2S_HS_INSTANCE; 149*34a0094bSVijendar Mukunda 150*34a0094bSVijendar Mukunda runtime->hw.channels_max = DUAL_CHANNEL; 151*34a0094bSVijendar Mukunda snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 152*34a0094bSVijendar Mukunda &constraints_channels); 153*34a0094bSVijendar Mukunda snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 154*34a0094bSVijendar Mukunda &constraints_rates); 155*34a0094bSVijendar Mukunda return 0; 156*34a0094bSVijendar Mukunda } 157*34a0094bSVijendar Mukunda 158*34a0094bSVijendar Mukunda static int acp5x_cs35l41_hw_params(struct snd_pcm_substream *substream, 159*34a0094bSVijendar Mukunda struct snd_pcm_hw_params *params) 160*34a0094bSVijendar Mukunda { 161*34a0094bSVijendar Mukunda struct snd_soc_pcm_runtime *rtd = substream->private_data; 162*34a0094bSVijendar Mukunda struct snd_soc_card *card = rtd->card; 163*34a0094bSVijendar Mukunda struct snd_soc_dai *codec_dai; 164*34a0094bSVijendar Mukunda int ret, i; 165*34a0094bSVijendar Mukunda unsigned int num_codecs = rtd->num_codecs; 166*34a0094bSVijendar Mukunda unsigned int bclk_val; 167*34a0094bSVijendar Mukunda 168*34a0094bSVijendar Mukunda for (i = 0; i < num_codecs; i++) { 169*34a0094bSVijendar Mukunda codec_dai = asoc_rtd_to_codec(rtd, i); 170*34a0094bSVijendar Mukunda if ((strcmp(codec_dai->name, "spi-VLV1776:00") == 0) || 171*34a0094bSVijendar Mukunda (strcmp(codec_dai->name, "spi-VLV1776:01") == 0)) { 172*34a0094bSVijendar Mukunda switch (params_rate(params)) { 173*34a0094bSVijendar Mukunda case 48000: 174*34a0094bSVijendar Mukunda bclk_val = 1536000; 175*34a0094bSVijendar Mukunda break; 176*34a0094bSVijendar Mukunda default: 177*34a0094bSVijendar Mukunda dev_err(card->dev, "Invalid Samplerate:0x%x\n", 178*34a0094bSVijendar Mukunda params_rate(params)); 179*34a0094bSVijendar Mukunda return -EINVAL; 180*34a0094bSVijendar Mukunda } 181*34a0094bSVijendar Mukunda ret = snd_soc_component_set_sysclk(codec_dai->component, 182*34a0094bSVijendar Mukunda 0, 0, bclk_val, SND_SOC_CLOCK_IN); 183*34a0094bSVijendar Mukunda if (ret < 0) { 184*34a0094bSVijendar Mukunda dev_err(card->dev, "failed to set sysclk for CS35l41 dai\n"); 185*34a0094bSVijendar Mukunda return ret; 186*34a0094bSVijendar Mukunda } 187*34a0094bSVijendar Mukunda } 188*34a0094bSVijendar Mukunda } 189*34a0094bSVijendar Mukunda 190*34a0094bSVijendar Mukunda return ret; 191*34a0094bSVijendar Mukunda } 192*34a0094bSVijendar Mukunda 193*34a0094bSVijendar Mukunda static const struct snd_soc_ops acp5x_8821_ops = { 194*34a0094bSVijendar Mukunda .startup = acp5x_8821_startup, 195*34a0094bSVijendar Mukunda .hw_params = acp5x_nau8821_hw_params, 196*34a0094bSVijendar Mukunda }; 197*34a0094bSVijendar Mukunda 198*34a0094bSVijendar Mukunda static const struct snd_soc_ops acp5x_cs35l41_play_ops = { 199*34a0094bSVijendar Mukunda .startup = acp5x_cs35l41_startup, 200*34a0094bSVijendar Mukunda .hw_params = acp5x_cs35l41_hw_params, 201*34a0094bSVijendar Mukunda }; 202*34a0094bSVijendar Mukunda 203*34a0094bSVijendar Mukunda static struct snd_soc_codec_conf cs35l41_conf[] = { 204*34a0094bSVijendar Mukunda { 205*34a0094bSVijendar Mukunda .dlc = COMP_CODEC_CONF("spi-VLV1776:00"), 206*34a0094bSVijendar Mukunda .name_prefix = "Left", 207*34a0094bSVijendar Mukunda }, 208*34a0094bSVijendar Mukunda { 209*34a0094bSVijendar Mukunda .dlc = COMP_CODEC_CONF("spi-VLV1776:01"), 210*34a0094bSVijendar Mukunda .name_prefix = "Right", 211*34a0094bSVijendar Mukunda }, 212*34a0094bSVijendar Mukunda }; 213*34a0094bSVijendar Mukunda 214*34a0094bSVijendar Mukunda SND_SOC_DAILINK_DEF(acp5x_i2s, 215*34a0094bSVijendar Mukunda DAILINK_COMP_ARRAY(COMP_CPU("acp5x_i2s_playcap.0"))); 216*34a0094bSVijendar Mukunda 217*34a0094bSVijendar Mukunda SND_SOC_DAILINK_DEF(acp5x_bt, 218*34a0094bSVijendar Mukunda DAILINK_COMP_ARRAY(COMP_CPU("acp5x_i2s_playcap.1"))); 219*34a0094bSVijendar Mukunda 220*34a0094bSVijendar Mukunda SND_SOC_DAILINK_DEF(nau8821, 221*34a0094bSVijendar Mukunda DAILINK_COMP_ARRAY(COMP_CODEC("i2c-NVTN2020:00", 222*34a0094bSVijendar Mukunda "nau8821-hifi"))); 223*34a0094bSVijendar Mukunda 224*34a0094bSVijendar Mukunda SND_SOC_DAILINK_DEF(cs35l41, 225*34a0094bSVijendar Mukunda DAILINK_COMP_ARRAY(COMP_CODEC("spi-VLV1776:00", "cs35l41-pcm"), 226*34a0094bSVijendar Mukunda COMP_CODEC("spi-VLV1776:01", "cs35l41-pcm"))); 227*34a0094bSVijendar Mukunda 228*34a0094bSVijendar Mukunda SND_SOC_DAILINK_DEF(platform, 229*34a0094bSVijendar Mukunda DAILINK_COMP_ARRAY(COMP_PLATFORM("acp5x_i2s_dma.0"))); 230*34a0094bSVijendar Mukunda 231*34a0094bSVijendar Mukunda static struct snd_soc_dai_link acp5x_dai[] = { 232*34a0094bSVijendar Mukunda { 233*34a0094bSVijendar Mukunda .name = "acp5x-8825-play", 234*34a0094bSVijendar Mukunda .stream_name = "Playback/Capture", 235*34a0094bSVijendar Mukunda .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 236*34a0094bSVijendar Mukunda SND_SOC_DAIFMT_CBC_CFC, 237*34a0094bSVijendar Mukunda .dpcm_playback = 1, 238*34a0094bSVijendar Mukunda .dpcm_capture = 1, 239*34a0094bSVijendar Mukunda .ops = &acp5x_8821_ops, 240*34a0094bSVijendar Mukunda .init = acp5x_8821_init, 241*34a0094bSVijendar Mukunda SND_SOC_DAILINK_REG(acp5x_i2s, nau8821, platform), 242*34a0094bSVijendar Mukunda }, 243*34a0094bSVijendar Mukunda { 244*34a0094bSVijendar Mukunda .name = "acp5x-CS35L41-Stereo", 245*34a0094bSVijendar Mukunda .stream_name = "CS35L41 Stereo Playback", 246*34a0094bSVijendar Mukunda .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 247*34a0094bSVijendar Mukunda SND_SOC_DAIFMT_CBC_CFC, 248*34a0094bSVijendar Mukunda .dpcm_playback = 1, 249*34a0094bSVijendar Mukunda .playback_only = 1, 250*34a0094bSVijendar Mukunda .ops = &acp5x_cs35l41_play_ops, 251*34a0094bSVijendar Mukunda .init = acp5x_cs35l41_init, 252*34a0094bSVijendar Mukunda SND_SOC_DAILINK_REG(acp5x_bt, cs35l41, platform), 253*34a0094bSVijendar Mukunda }, 254*34a0094bSVijendar Mukunda }; 255*34a0094bSVijendar Mukunda 256*34a0094bSVijendar Mukunda static int platform_clock_control(struct snd_soc_dapm_widget *w, 257*34a0094bSVijendar Mukunda struct snd_kcontrol *k, int event) 258*34a0094bSVijendar Mukunda { 259*34a0094bSVijendar Mukunda struct snd_soc_dapm_context *dapm = w->dapm; 260*34a0094bSVijendar Mukunda struct snd_soc_card *card = dapm->card; 261*34a0094bSVijendar Mukunda struct snd_soc_dai *codec_dai; 262*34a0094bSVijendar Mukunda int ret = 0; 263*34a0094bSVijendar Mukunda 264*34a0094bSVijendar Mukunda codec_dai = snd_soc_card_get_codec_dai(card, ACP5X_NUVOTON_CODEC_DAI); 265*34a0094bSVijendar Mukunda if (!codec_dai) { 266*34a0094bSVijendar Mukunda dev_err(card->dev, "Codec dai not found\n"); 267*34a0094bSVijendar Mukunda return -EIO; 268*34a0094bSVijendar Mukunda } 269*34a0094bSVijendar Mukunda 270*34a0094bSVijendar Mukunda if (SND_SOC_DAPM_EVENT_OFF(event)) { 271*34a0094bSVijendar Mukunda ret = snd_soc_dai_set_sysclk(codec_dai, NAU8821_CLK_INTERNAL, 272*34a0094bSVijendar Mukunda 0, SND_SOC_CLOCK_IN); 273*34a0094bSVijendar Mukunda if (ret < 0) { 274*34a0094bSVijendar Mukunda dev_err(card->dev, "set sysclk err = %d\n", ret); 275*34a0094bSVijendar Mukunda return -EIO; 276*34a0094bSVijendar Mukunda } 277*34a0094bSVijendar Mukunda } 278*34a0094bSVijendar Mukunda return ret; 279*34a0094bSVijendar Mukunda } 280*34a0094bSVijendar Mukunda 281*34a0094bSVijendar Mukunda static const struct snd_kcontrol_new acp5x_8821_controls[] = { 282*34a0094bSVijendar Mukunda SOC_DAPM_PIN_SWITCH("Headphone"), 283*34a0094bSVijendar Mukunda SOC_DAPM_PIN_SWITCH("Headset Mic"), 284*34a0094bSVijendar Mukunda SOC_DAPM_PIN_SWITCH("Int Mic"), 285*34a0094bSVijendar Mukunda }; 286*34a0094bSVijendar Mukunda 287*34a0094bSVijendar Mukunda static const struct snd_soc_dapm_widget acp5x_8821_widgets[] = { 288*34a0094bSVijendar Mukunda SND_SOC_DAPM_HP("Headphone", NULL), 289*34a0094bSVijendar Mukunda SND_SOC_DAPM_MIC("Headset Mic", NULL), 290*34a0094bSVijendar Mukunda SND_SOC_DAPM_MIC("Int Mic", NULL), 291*34a0094bSVijendar Mukunda SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, 292*34a0094bSVijendar Mukunda platform_clock_control, SND_SOC_DAPM_POST_PMD), 293*34a0094bSVijendar Mukunda }; 294*34a0094bSVijendar Mukunda 295*34a0094bSVijendar Mukunda static const struct snd_soc_dapm_route acp5x_8821_audio_route[] = { 296*34a0094bSVijendar Mukunda /* HP jack connectors - unknown if we have jack detection */ 297*34a0094bSVijendar Mukunda { "Headphone", NULL, "HPOL" }, 298*34a0094bSVijendar Mukunda { "Headphone", NULL, "HPOR" }, 299*34a0094bSVijendar Mukunda { "MICL", NULL, "Headset Mic" }, 300*34a0094bSVijendar Mukunda { "MICR", NULL, "Headset Mic" }, 301*34a0094bSVijendar Mukunda { "DMIC", NULL, "Int Mic" }, 302*34a0094bSVijendar Mukunda 303*34a0094bSVijendar Mukunda { "Headphone", NULL, "Platform Clock" }, 304*34a0094bSVijendar Mukunda { "Headset Mic", NULL, "Platform Clock" }, 305*34a0094bSVijendar Mukunda { "Int Mic", NULL, "Platform Clock" }, 306*34a0094bSVijendar Mukunda }; 307*34a0094bSVijendar Mukunda 308*34a0094bSVijendar Mukunda static struct snd_soc_card acp5x_card = { 309*34a0094bSVijendar Mukunda .name = "acp5x", 310*34a0094bSVijendar Mukunda .owner = THIS_MODULE, 311*34a0094bSVijendar Mukunda .dai_link = acp5x_dai, 312*34a0094bSVijendar Mukunda .num_links = ARRAY_SIZE(acp5x_dai), 313*34a0094bSVijendar Mukunda .dapm_widgets = acp5x_8821_widgets, 314*34a0094bSVijendar Mukunda .num_dapm_widgets = ARRAY_SIZE(acp5x_8821_widgets), 315*34a0094bSVijendar Mukunda .dapm_routes = acp5x_8821_audio_route, 316*34a0094bSVijendar Mukunda .num_dapm_routes = ARRAY_SIZE(acp5x_8821_audio_route), 317*34a0094bSVijendar Mukunda .codec_conf = cs35l41_conf, 318*34a0094bSVijendar Mukunda .num_configs = ARRAY_SIZE(cs35l41_conf), 319*34a0094bSVijendar Mukunda .controls = acp5x_8821_controls, 320*34a0094bSVijendar Mukunda .num_controls = ARRAY_SIZE(acp5x_8821_controls), 321*34a0094bSVijendar Mukunda }; 322*34a0094bSVijendar Mukunda 323*34a0094bSVijendar Mukunda 324*34a0094bSVijendar Mukunda static int acp5x_vg_quirk_cb(const struct dmi_system_id *id) 325*34a0094bSVijendar Mukunda { 326*34a0094bSVijendar Mukunda acp5x_machine_id = VG_JUPITER; 327*34a0094bSVijendar Mukunda return 1; 328*34a0094bSVijendar Mukunda } 329*34a0094bSVijendar Mukunda 330*34a0094bSVijendar Mukunda static const struct dmi_system_id acp5x_vg_quirk_table[] = { 331*34a0094bSVijendar Mukunda { 332*34a0094bSVijendar Mukunda .callback = acp5x_vg_quirk_cb, 333*34a0094bSVijendar Mukunda .matches = { 334*34a0094bSVijendar Mukunda DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "Valve"), 335*34a0094bSVijendar Mukunda DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Jupiter"), 336*34a0094bSVijendar Mukunda } 337*34a0094bSVijendar Mukunda }, 338*34a0094bSVijendar Mukunda {} 339*34a0094bSVijendar Mukunda }; 340*34a0094bSVijendar Mukunda 341*34a0094bSVijendar Mukunda static int acp5x_probe(struct platform_device *pdev) 342*34a0094bSVijendar Mukunda { 343*34a0094bSVijendar Mukunda int ret; 344*34a0094bSVijendar Mukunda struct acp5x_platform_info *machine; 345*34a0094bSVijendar Mukunda struct snd_soc_card *card; 346*34a0094bSVijendar Mukunda 347*34a0094bSVijendar Mukunda machine = devm_kzalloc(&pdev->dev, sizeof(struct acp5x_platform_info), 348*34a0094bSVijendar Mukunda GFP_KERNEL); 349*34a0094bSVijendar Mukunda if (!machine) 350*34a0094bSVijendar Mukunda return -ENOMEM; 351*34a0094bSVijendar Mukunda 352*34a0094bSVijendar Mukunda dmi_check_system(acp5x_vg_quirk_table); 353*34a0094bSVijendar Mukunda switch(acp5x_machine_id) { 354*34a0094bSVijendar Mukunda case VG_JUPITER: 355*34a0094bSVijendar Mukunda card = &acp5x_card; 356*34a0094bSVijendar Mukunda acp5x_card.dev = &pdev->dev; 357*34a0094bSVijendar Mukunda break; 358*34a0094bSVijendar Mukunda default: 359*34a0094bSVijendar Mukunda return -ENODEV; 360*34a0094bSVijendar Mukunda } 361*34a0094bSVijendar Mukunda platform_set_drvdata(pdev, card); 362*34a0094bSVijendar Mukunda snd_soc_card_set_drvdata(card, machine); 363*34a0094bSVijendar Mukunda 364*34a0094bSVijendar Mukunda ret = devm_snd_soc_register_card(&pdev->dev, card); 365*34a0094bSVijendar Mukunda if (ret) { 366*34a0094bSVijendar Mukunda return dev_err_probe(&pdev->dev, ret, 367*34a0094bSVijendar Mukunda "snd_soc_register_card(%s) failed\n", 368*34a0094bSVijendar Mukunda acp5x_card.name); 369*34a0094bSVijendar Mukunda } 370*34a0094bSVijendar Mukunda return 0; 371*34a0094bSVijendar Mukunda } 372*34a0094bSVijendar Mukunda 373*34a0094bSVijendar Mukunda static struct platform_driver acp5x_mach_driver = { 374*34a0094bSVijendar Mukunda .driver = { 375*34a0094bSVijendar Mukunda .name = "acp5x_mach", 376*34a0094bSVijendar Mukunda .pm = &snd_soc_pm_ops, 377*34a0094bSVijendar Mukunda }, 378*34a0094bSVijendar Mukunda .probe = acp5x_probe, 379*34a0094bSVijendar Mukunda }; 380*34a0094bSVijendar Mukunda 381*34a0094bSVijendar Mukunda module_platform_driver(acp5x_mach_driver); 382*34a0094bSVijendar Mukunda 383*34a0094bSVijendar Mukunda MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); 384*34a0094bSVijendar Mukunda MODULE_DESCRIPTION("NAU8821 & CS35L41 audio support"); 385*34a0094bSVijendar Mukunda MODULE_LICENSE("GPL v2"); 386*34a0094bSVijendar Mukunda MODULE_ALIAS("platform:" DRV_NAME); 387