1 /* 2 * bytcht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail 3 * platforms with Everest ES8316 SoC 4 * 5 * Copyright (C) 2017 Endless Mobile, Inc. 6 * Authors: David Yang <yangxiaohua@everest-semi.com>, 7 * Daniel Drake <drake@endlessm.com> 8 * 9 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; version 2 of the License. 14 * 15 * This program is distributed in the hope that it will be useful, but 16 * WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * General Public License for more details. 19 * 20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 */ 22 #include <linux/acpi.h> 23 #include <linux/clk.h> 24 #include <linux/device.h> 25 #include <linux/dmi.h> 26 #include <linux/gpio/consumer.h> 27 #include <linux/i2c.h> 28 #include <linux/init.h> 29 #include <linux/input.h> 30 #include <linux/module.h> 31 #include <linux/platform_device.h> 32 #include <linux/slab.h> 33 #include <asm/cpu_device_id.h> 34 #include <asm/intel-family.h> 35 #include <asm/platform_sst_audio.h> 36 #include <sound/jack.h> 37 #include <sound/pcm.h> 38 #include <sound/pcm_params.h> 39 #include <sound/soc.h> 40 #include <sound/soc-acpi.h> 41 #include "../atom/sst-atom-controls.h" 42 #include "../common/sst-dsp.h" 43 44 /* jd-inv + terminating entry */ 45 #define MAX_NO_PROPS 2 46 47 struct byt_cht_es8316_private { 48 struct clk *mclk; 49 struct snd_soc_jack jack; 50 struct gpio_desc *speaker_en_gpio; 51 bool speaker_en; 52 }; 53 54 enum { 55 BYT_CHT_ES8316_INTMIC_IN1_MAP, 56 BYT_CHT_ES8316_INTMIC_IN2_MAP, 57 }; 58 59 #define BYT_CHT_ES8316_MAP(quirk) ((quirk) & GENMASK(3, 0)) 60 #define BYT_CHT_ES8316_SSP0 BIT(16) 61 #define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) 62 #define BYT_CHT_ES8316_JD_INVERTED BIT(18) 63 64 static unsigned long quirk; 65 66 static int quirk_override = -1; 67 module_param_named(quirk, quirk_override, int, 0444); 68 MODULE_PARM_DESC(quirk, "Board-specific quirk override"); 69 70 static void log_quirks(struct device *dev) 71 { 72 if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN1_MAP) 73 dev_info(dev, "quirk IN1_MAP enabled"); 74 if (BYT_CHT_ES8316_MAP(quirk) == BYT_CHT_ES8316_INTMIC_IN2_MAP) 75 dev_info(dev, "quirk IN2_MAP enabled"); 76 if (quirk & BYT_CHT_ES8316_SSP0) 77 dev_info(dev, "quirk SSP0 enabled"); 78 if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) 79 dev_info(dev, "quirk MONO_SPEAKER enabled\n"); 80 if (quirk & BYT_CHT_ES8316_JD_INVERTED) 81 dev_info(dev, "quirk JD_INVERTED enabled\n"); 82 } 83 84 static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, 85 struct snd_kcontrol *kcontrol, int event) 86 { 87 struct snd_soc_card *card = w->dapm->card; 88 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 89 90 if (SND_SOC_DAPM_EVENT_ON(event)) 91 priv->speaker_en = true; 92 else 93 priv->speaker_en = false; 94 95 gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); 96 97 return 0; 98 } 99 100 static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { 101 SND_SOC_DAPM_SPK("Speaker", NULL), 102 SND_SOC_DAPM_HP("Headphone", NULL), 103 SND_SOC_DAPM_MIC("Headset Mic", NULL), 104 SND_SOC_DAPM_MIC("Internal Mic", NULL), 105 106 SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, 107 byt_cht_es8316_speaker_power_event, 108 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), 109 }; 110 111 static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { 112 {"Headphone", NULL, "HPOL"}, 113 {"Headphone", NULL, "HPOR"}, 114 115 /* 116 * There is no separate speaker output instead the speakers are muxed to 117 * the HP outputs. The mux is controlled by the "Speaker Power" supply. 118 */ 119 {"Speaker", NULL, "HPOL"}, 120 {"Speaker", NULL, "HPOR"}, 121 {"Speaker", NULL, "Speaker Power"}, 122 }; 123 124 static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = { 125 {"MIC1", NULL, "Internal Mic"}, 126 {"MIC2", NULL, "Headset Mic"}, 127 }; 128 129 static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = { 130 {"MIC2", NULL, "Internal Mic"}, 131 {"MIC1", NULL, "Headset Mic"}, 132 }; 133 134 static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { 135 {"Playback", NULL, "ssp0 Tx"}, 136 {"ssp0 Tx", NULL, "modem_out"}, 137 {"modem_in", NULL, "ssp0 Rx"}, 138 {"ssp0 Rx", NULL, "Capture"}, 139 }; 140 141 static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { 142 {"Playback", NULL, "ssp2 Tx"}, 143 {"ssp2 Tx", NULL, "codec_out0"}, 144 {"ssp2 Tx", NULL, "codec_out1"}, 145 {"codec_in0", NULL, "ssp2 Rx" }, 146 {"codec_in1", NULL, "ssp2 Rx" }, 147 {"ssp2 Rx", NULL, "Capture"}, 148 }; 149 150 static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { 151 SOC_DAPM_PIN_SWITCH("Speaker"), 152 SOC_DAPM_PIN_SWITCH("Headphone"), 153 SOC_DAPM_PIN_SWITCH("Headset Mic"), 154 SOC_DAPM_PIN_SWITCH("Internal Mic"), 155 }; 156 157 static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { 158 { 159 .pin = "Headphone", 160 .mask = SND_JACK_HEADPHONE, 161 }, 162 { 163 .pin = "Headset Mic", 164 .mask = SND_JACK_MICROPHONE, 165 }, 166 }; 167 168 static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) 169 { 170 struct snd_soc_component *codec = runtime->codec_dai->component; 171 struct snd_soc_card *card = runtime->card; 172 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 173 const struct snd_soc_dapm_route *custom_map; 174 int num_routes; 175 int ret; 176 177 card->dapm.idle_bias_off = true; 178 179 switch (BYT_CHT_ES8316_MAP(quirk)) { 180 case BYT_CHT_ES8316_INTMIC_IN1_MAP: 181 default: 182 custom_map = byt_cht_es8316_intmic_in1_map; 183 num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map); 184 break; 185 case BYT_CHT_ES8316_INTMIC_IN2_MAP: 186 custom_map = byt_cht_es8316_intmic_in2_map; 187 num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); 188 break; 189 } 190 ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); 191 if (ret) 192 return ret; 193 194 if (quirk & BYT_CHT_ES8316_SSP0) { 195 custom_map = byt_cht_es8316_ssp0_map; 196 num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); 197 } else { 198 custom_map = byt_cht_es8316_ssp2_map; 199 num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); 200 } 201 ret = snd_soc_dapm_add_routes(&card->dapm, custom_map, num_routes); 202 if (ret) 203 return ret; 204 205 /* 206 * The firmware might enable the clock at boot (this information 207 * may or may not be reflected in the enable clock register). 208 * To change the rate we must disable the clock first to cover these 209 * cases. Due to common clock framework restrictions that do not allow 210 * to disable a clock that has not been enabled, we need to enable 211 * the clock first. 212 */ 213 ret = clk_prepare_enable(priv->mclk); 214 if (!ret) 215 clk_disable_unprepare(priv->mclk); 216 217 ret = clk_set_rate(priv->mclk, 19200000); 218 if (ret) 219 dev_err(card->dev, "unable to set MCLK rate\n"); 220 221 ret = clk_prepare_enable(priv->mclk); 222 if (ret) 223 dev_err(card->dev, "unable to enable MCLK\n"); 224 225 ret = snd_soc_dai_set_sysclk(runtime->codec_dai, 0, 19200000, 226 SND_SOC_CLOCK_IN); 227 if (ret < 0) { 228 dev_err(card->dev, "can't set codec clock %d\n", ret); 229 return ret; 230 } 231 232 ret = snd_soc_card_jack_new(card, "Headset", 233 SND_JACK_HEADSET | SND_JACK_BTN_0, 234 &priv->jack, byt_cht_es8316_jack_pins, 235 ARRAY_SIZE(byt_cht_es8316_jack_pins)); 236 if (ret) { 237 dev_err(card->dev, "jack creation failed %d\n", ret); 238 return ret; 239 } 240 241 snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 242 snd_soc_component_set_jack(codec, &priv->jack, NULL); 243 244 return 0; 245 } 246 247 static const struct snd_soc_pcm_stream byt_cht_es8316_dai_params = { 248 .formats = SNDRV_PCM_FMTBIT_S24_LE, 249 .rate_min = 48000, 250 .rate_max = 48000, 251 .channels_min = 2, 252 .channels_max = 2, 253 }; 254 255 static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, 256 struct snd_pcm_hw_params *params) 257 { 258 struct snd_interval *rate = hw_param_interval(params, 259 SNDRV_PCM_HW_PARAM_RATE); 260 struct snd_interval *channels = hw_param_interval(params, 261 SNDRV_PCM_HW_PARAM_CHANNELS); 262 int ret, bits; 263 264 /* The DSP will covert the FE rate to 48k, stereo */ 265 rate->min = rate->max = 48000; 266 channels->min = channels->max = 2; 267 268 if (quirk & BYT_CHT_ES8316_SSP0) { 269 /* set SSP0 to 16-bit */ 270 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); 271 bits = 16; 272 } else { 273 /* set SSP2 to 24-bit */ 274 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); 275 bits = 24; 276 } 277 278 /* 279 * Default mode for SSP configuration is TDM 4 slot, override config 280 * with explicit setting to I2S 2ch 24-bit. The word length is set with 281 * dai_set_tdm_slot() since there is no other API exposed 282 */ 283 ret = snd_soc_dai_set_fmt(rtd->cpu_dai, 284 SND_SOC_DAIFMT_I2S | 285 SND_SOC_DAIFMT_NB_NF | 286 SND_SOC_DAIFMT_CBS_CFS 287 ); 288 if (ret < 0) { 289 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); 290 return ret; 291 } 292 293 ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, bits); 294 if (ret < 0) { 295 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); 296 return ret; 297 } 298 299 return 0; 300 } 301 302 static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream) 303 { 304 return snd_pcm_hw_constraint_single(substream->runtime, 305 SNDRV_PCM_HW_PARAM_RATE, 48000); 306 } 307 308 static const struct snd_soc_ops byt_cht_es8316_aif1_ops = { 309 .startup = byt_cht_es8316_aif1_startup, 310 }; 311 312 static struct snd_soc_dai_link byt_cht_es8316_dais[] = { 313 [MERR_DPCM_AUDIO] = { 314 .name = "Audio Port", 315 .stream_name = "Audio", 316 .cpu_dai_name = "media-cpu-dai", 317 .codec_dai_name = "snd-soc-dummy-dai", 318 .codec_name = "snd-soc-dummy", 319 .platform_name = "sst-mfld-platform", 320 .nonatomic = true, 321 .dynamic = 1, 322 .dpcm_playback = 1, 323 .dpcm_capture = 1, 324 .ops = &byt_cht_es8316_aif1_ops, 325 }, 326 327 [MERR_DPCM_DEEP_BUFFER] = { 328 .name = "Deep-Buffer Audio Port", 329 .stream_name = "Deep-Buffer Audio", 330 .cpu_dai_name = "deepbuffer-cpu-dai", 331 .codec_dai_name = "snd-soc-dummy-dai", 332 .codec_name = "snd-soc-dummy", 333 .platform_name = "sst-mfld-platform", 334 .nonatomic = true, 335 .dynamic = 1, 336 .dpcm_playback = 1, 337 .ops = &byt_cht_es8316_aif1_ops, 338 }, 339 340 /* back ends */ 341 { 342 /* Only SSP2 has been tested here, so BYT-CR platforms that 343 * require SSP0 will not work. 344 */ 345 .name = "SSP2-Codec", 346 .id = 0, 347 .cpu_dai_name = "ssp2-port", 348 .platform_name = "sst-mfld-platform", 349 .no_pcm = 1, 350 .codec_dai_name = "ES8316 HiFi", 351 .codec_name = "i2c-ESSX8316:00", 352 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 353 | SND_SOC_DAIFMT_CBS_CFS, 354 .be_hw_params_fixup = byt_cht_es8316_codec_fixup, 355 .nonatomic = true, 356 .dpcm_playback = 1, 357 .dpcm_capture = 1, 358 .init = byt_cht_es8316_init, 359 }, 360 }; 361 362 363 /* SoC card */ 364 static char codec_name[SND_ACPI_I2C_ID_LEN]; 365 static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ 366 367 static int byt_cht_es8316_suspend(struct snd_soc_card *card) 368 { 369 struct snd_soc_component *component; 370 371 for_each_card_components(card, component) { 372 if (!strcmp(component->name, codec_name)) { 373 dev_dbg(component->dev, "disabling jack detect before suspend\n"); 374 snd_soc_component_set_jack(component, NULL, NULL); 375 break; 376 } 377 } 378 379 return 0; 380 } 381 382 static int byt_cht_es8316_resume(struct snd_soc_card *card) 383 { 384 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 385 struct snd_soc_component *component; 386 387 for_each_card_components(card, component) { 388 if (!strcmp(component->name, codec_name)) { 389 dev_dbg(component->dev, "re-enabling jack detect after resume\n"); 390 snd_soc_component_set_jack(component, &priv->jack, NULL); 391 break; 392 } 393 } 394 395 /* 396 * Some Cherry Trail boards with an ES8316 codec have a bug in their 397 * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods 398 * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown 399 * that this really is a bug and the GPIO has no influence on the 400 * touchscreen at all. 401 * 402 * The silead.c touchscreen driver does not support runtime suspend, so 403 * the GPIO can only be changed underneath us during a system suspend. 404 * This resume() function runs from a pm complete() callback, and thus 405 * is guaranteed to run after the touchscreen driver/ACPI-subsys has 406 * brought the touchscreen back up again (and thus changed the GPIO). 407 * 408 * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when 409 * requesting the GPIO and we set its value here to undo any changes 410 * done by the touchscreen's broken _PS0 ACPI method. 411 */ 412 gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); 413 414 return 0; 415 } 416 417 static struct snd_soc_card byt_cht_es8316_card = { 418 .name = "bytcht-es8316", 419 .owner = THIS_MODULE, 420 .dai_link = byt_cht_es8316_dais, 421 .num_links = ARRAY_SIZE(byt_cht_es8316_dais), 422 .dapm_widgets = byt_cht_es8316_widgets, 423 .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets), 424 .dapm_routes = byt_cht_es8316_audio_map, 425 .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map), 426 .controls = byt_cht_es8316_controls, 427 .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), 428 .fully_routed = true, 429 .suspend_pre = byt_cht_es8316_suspend, 430 .resume_post = byt_cht_es8316_resume, 431 }; 432 433 static const struct x86_cpu_id baytrail_cpu_ids[] = { 434 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT }, /* Valleyview */ 435 {} 436 }; 437 438 static const struct acpi_gpio_params first_gpio = { 0, 0, false }; 439 440 static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { 441 { "speaker-enable-gpios", &first_gpio, 1 }, 442 { }, 443 }; 444 445 /* Please keep this list alphabetically sorted */ 446 static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { 447 { /* Teclast X98 Plus II */ 448 .matches = { 449 DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), 450 DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), 451 }, 452 .driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN1_MAP 453 | BYT_CHT_ES8316_JD_INVERTED), 454 }, 455 {} 456 }; 457 458 static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) 459 { 460 static const char * const mic_name[] = { "in1", "in2" }; 461 struct property_entry props[MAX_NO_PROPS] = {}; 462 struct byt_cht_es8316_private *priv; 463 const struct dmi_system_id *dmi_id; 464 struct device *dev = &pdev->dev; 465 struct snd_soc_acpi_mach *mach; 466 const char *platform_name; 467 struct acpi_device *adev; 468 struct device *codec_dev; 469 unsigned int cnt = 0; 470 int dai_index = 0; 471 int i; 472 int ret = 0; 473 474 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 475 if (!priv) 476 return -ENOMEM; 477 478 mach = dev->platform_data; 479 /* fix index of codec dai */ 480 for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { 481 if (!strcmp(byt_cht_es8316_dais[i].codec_name, 482 "i2c-ESSX8316:00")) { 483 dai_index = i; 484 break; 485 } 486 } 487 488 /* fixup codec name based on HID */ 489 adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); 490 if (adev) { 491 snprintf(codec_name, sizeof(codec_name), 492 "i2c-%s", acpi_dev_name(adev)); 493 put_device(&adev->dev); 494 byt_cht_es8316_dais[dai_index].codec_name = codec_name; 495 } 496 497 /* override plaform name, if required */ 498 platform_name = mach->mach_params.platform; 499 500 ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, 501 platform_name); 502 if (ret) 503 return ret; 504 505 /* Check for BYTCR or other platform and setup quirks */ 506 dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); 507 if (dmi_id) { 508 quirk = (unsigned long)dmi_id->driver_data; 509 } else if (x86_match_cpu(baytrail_cpu_ids) && 510 mach->mach_params.acpi_ipc_irq_index == 0) { 511 /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ 512 quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | 513 BYT_CHT_ES8316_MONO_SPEAKER; 514 } else { 515 /* Others default to internal-mic-in1-map, mono-speaker */ 516 quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | 517 BYT_CHT_ES8316_MONO_SPEAKER; 518 } 519 if (quirk_override != -1) { 520 dev_info(dev, "Overriding quirk 0x%x => 0x%x\n", 521 (unsigned int)quirk, 522 quirk_override); 523 quirk = quirk_override; 524 } 525 log_quirks(dev); 526 527 if (quirk & BYT_CHT_ES8316_SSP0) 528 byt_cht_es8316_dais[dai_index].cpu_dai_name = "ssp0-port"; 529 530 /* get the clock */ 531 priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); 532 if (IS_ERR(priv->mclk)) { 533 ret = PTR_ERR(priv->mclk); 534 dev_err(dev, "clk_get pmc_plt_clk_3 failed: %d\n", ret); 535 return ret; 536 } 537 538 /* get speaker enable GPIO */ 539 codec_dev = bus_find_device_by_name(&i2c_bus_type, NULL, codec_name); 540 if (!codec_dev) 541 return -EPROBE_DEFER; 542 543 if (quirk & BYT_CHT_ES8316_JD_INVERTED) 544 props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); 545 546 if (cnt) { 547 ret = device_add_properties(codec_dev, props); 548 if (ret) 549 return ret; 550 } 551 552 devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); 553 priv->speaker_en_gpio = 554 gpiod_get_index(codec_dev, "speaker-enable", 0, 555 /* see comment in byt_cht_es8316_resume */ 556 GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); 557 put_device(codec_dev); 558 559 if (IS_ERR(priv->speaker_en_gpio)) { 560 ret = PTR_ERR(priv->speaker_en_gpio); 561 switch (ret) { 562 case -ENOENT: 563 priv->speaker_en_gpio = NULL; 564 break; 565 default: 566 dev_err(dev, "get speaker GPIO failed: %d\n", ret); 567 /* fall through */ 568 case -EPROBE_DEFER: 569 return ret; 570 } 571 } 572 573 /* register the soc card */ 574 snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", 575 (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", 576 mic_name[BYT_CHT_ES8316_MAP(quirk)]); 577 byt_cht_es8316_card.long_name = long_name; 578 byt_cht_es8316_card.dev = dev; 579 snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); 580 581 ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); 582 if (ret) { 583 gpiod_put(priv->speaker_en_gpio); 584 dev_err(dev, "snd_soc_register_card failed: %d\n", ret); 585 return ret; 586 } 587 platform_set_drvdata(pdev, &byt_cht_es8316_card); 588 return 0; 589 } 590 591 static int snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) 592 { 593 struct snd_soc_card *card = platform_get_drvdata(pdev); 594 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 595 596 gpiod_put(priv->speaker_en_gpio); 597 return 0; 598 } 599 600 static struct platform_driver snd_byt_cht_es8316_mc_driver = { 601 .driver = { 602 .name = "bytcht_es8316", 603 }, 604 .probe = snd_byt_cht_es8316_mc_probe, 605 .remove = snd_byt_cht_es8316_mc_remove, 606 }; 607 608 module_platform_driver(snd_byt_cht_es8316_mc_driver); 609 MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); 610 MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); 611 MODULE_LICENSE("GPL v2"); 612 MODULE_ALIAS("platform:bytcht_es8316"); 613