FILE
bytcht_es8316.c
File preview with syntax highlighting.
linux-6.19.14/sound/soc/intel/boards/bytcht_es8316.c
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * bytcht_es8316.c - ASoc Machine driver for Intel Baytrail/Cherrytrail 4 * platforms with Everest ES8316 SoC 5 * 6 * Copyright (C) 2017 Endless Mobile, Inc. 7 * Authors: David Yang <yangxiaohua@everest-semi.com>, 8 * Daniel Drake <drake@endlessm.com> 9 * 10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 11 * 12 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 */ 14#include <linux/acpi.h> 15#include <linux/clk.h> 16#include <linux/device.h> 17#include <linux/dmi.h> 18#include <linux/gpio/consumer.h> 19#include <linux/i2c.h> 20#include <linux/init.h> 21#include <linux/input.h> 22#include <linux/module.h> 23#include <linux/platform_device.h> 24#include <linux/slab.h> 25#include <sound/jack.h> 26#include <sound/pcm.h> 27#include <sound/pcm_params.h> 28#include <sound/soc.h> 29#include <sound/soc-acpi.h> 30#include "../../codecs/es83xx-dsm-common.h" 31#include "../atom/sst-atom-controls.h" 32#include "../common/soc-intel-quirks.h" 33 34/* jd-inv + terminating entry */ 35#define MAX_NO_PROPS 2 36 37struct byt_cht_es8316_private { 38 struct clk *mclk; 39 struct snd_soc_jack jack; 40 struct gpio_desc *speaker_en_gpio; 41 struct device *codec_dev; 42 bool speaker_en; 43}; 44 45enum { 46 BYT_CHT_ES8316_INTMIC_IN1_MAP, 47 BYT_CHT_ES8316_INTMIC_IN2_MAP, 48}; 49 50#define BYT_CHT_ES8316_MAP_MASK GENMASK(3, 0) 51#define BYT_CHT_ES8316_MAP(quirk) ((quirk) & BYT_CHT_ES8316_MAP_MASK) 52#define BYT_CHT_ES8316_SSP0 BIT(16) 53#define BYT_CHT_ES8316_MONO_SPEAKER BIT(17) 54#define BYT_CHT_ES8316_JD_INVERTED BIT(18) 55 56static unsigned long quirk; 57 58static int quirk_override = -1; 59module_param_named(quirk, quirk_override, int, 0444); 60MODULE_PARM_DESC(quirk, "Board-specific quirk override"); 61 62static void log_quirks(struct device *dev) 63{ 64 int map; 65 66 map = BYT_CHT_ES8316_MAP(quirk); 67 switch (map) { 68 case BYT_CHT_ES8316_INTMIC_IN1_MAP: 69 dev_info(dev, "quirk IN1_MAP enabled"); 70 break; 71 case BYT_CHT_ES8316_INTMIC_IN2_MAP: 72 dev_info(dev, "quirk IN2_MAP enabled"); 73 break; 74 default: 75 dev_warn_once(dev, "quirk sets invalid input map: 0x%x, default to INTMIC_IN1_MAP\n", map); 76 quirk &= ~BYT_CHT_ES8316_MAP_MASK; 77 quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP; 78 break; 79 } 80 81 if (quirk & BYT_CHT_ES8316_SSP0) 82 dev_info(dev, "quirk SSP0 enabled"); 83 if (quirk & BYT_CHT_ES8316_MONO_SPEAKER) 84 dev_info(dev, "quirk MONO_SPEAKER enabled\n"); 85 if (quirk & BYT_CHT_ES8316_JD_INVERTED) 86 dev_info(dev, "quirk JD_INVERTED enabled\n"); 87} 88 89static int byt_cht_es8316_speaker_power_event(struct snd_soc_dapm_widget *w, 90 struct snd_kcontrol *kcontrol, int event) 91{ 92 struct snd_soc_card *card = snd_soc_dapm_to_card(w->dapm); 93 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 94 95 if (SND_SOC_DAPM_EVENT_ON(event)) 96 priv->speaker_en = true; 97 else 98 priv->speaker_en = false; 99 100 gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); 101 102 return 0; 103} 104 105static const struct snd_soc_dapm_widget byt_cht_es8316_widgets[] = { 106 SND_SOC_DAPM_SPK("Speaker", NULL), 107 SND_SOC_DAPM_HP("Headphone", NULL), 108 SND_SOC_DAPM_MIC("Headset Mic", NULL), 109 SND_SOC_DAPM_MIC("Internal Mic", NULL), 110 111 SND_SOC_DAPM_SUPPLY("Speaker Power", SND_SOC_NOPM, 0, 0, 112 byt_cht_es8316_speaker_power_event, 113 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), 114}; 115 116static const struct snd_soc_dapm_route byt_cht_es8316_audio_map[] = { 117 {"Headphone", NULL, "HPOL"}, 118 {"Headphone", NULL, "HPOR"}, 119 120 /* 121 * There is no separate speaker output instead the speakers are muxed to 122 * the HP outputs. The mux is controlled by the "Speaker Power" supply. 123 */ 124 {"Speaker", NULL, "HPOL"}, 125 {"Speaker", NULL, "HPOR"}, 126 {"Speaker", NULL, "Speaker Power"}, 127}; 128 129static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in1_map[] = { 130 {"MIC1", NULL, "Internal Mic"}, 131 {"MIC2", NULL, "Headset Mic"}, 132}; 133 134static const struct snd_soc_dapm_route byt_cht_es8316_intmic_in2_map[] = { 135 {"MIC2", NULL, "Internal Mic"}, 136 {"MIC1", NULL, "Headset Mic"}, 137}; 138 139static const struct snd_soc_dapm_route byt_cht_es8316_ssp0_map[] = { 140 {"Playback", NULL, "ssp0 Tx"}, 141 {"ssp0 Tx", NULL, "modem_out"}, 142 {"modem_in", NULL, "ssp0 Rx"}, 143 {"ssp0 Rx", NULL, "Capture"}, 144}; 145 146static const struct snd_soc_dapm_route byt_cht_es8316_ssp2_map[] = { 147 {"Playback", NULL, "ssp2 Tx"}, 148 {"ssp2 Tx", NULL, "codec_out0"}, 149 {"ssp2 Tx", NULL, "codec_out1"}, 150 {"codec_in0", NULL, "ssp2 Rx" }, 151 {"codec_in1", NULL, "ssp2 Rx" }, 152 {"ssp2 Rx", NULL, "Capture"}, 153}; 154 155static const struct snd_kcontrol_new byt_cht_es8316_controls[] = { 156 SOC_DAPM_PIN_SWITCH("Speaker"), 157 SOC_DAPM_PIN_SWITCH("Headphone"), 158 SOC_DAPM_PIN_SWITCH("Headset Mic"), 159 SOC_DAPM_PIN_SWITCH("Internal Mic"), 160}; 161 162static struct snd_soc_jack_pin byt_cht_es8316_jack_pins[] = { 163 { 164 .pin = "Headphone", 165 .mask = SND_JACK_HEADPHONE, 166 }, 167 { 168 .pin = "Headset Mic", 169 .mask = SND_JACK_MICROPHONE, 170 }, 171}; 172 173static int byt_cht_es8316_init(struct snd_soc_pcm_runtime *runtime) 174{ 175 struct snd_soc_component *codec = snd_soc_rtd_to_codec(runtime, 0)->component; 176 struct snd_soc_card *card = runtime->card; 177 struct snd_soc_dapm_context *dapm = snd_soc_card_to_dapm(card); 178 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 179 const struct snd_soc_dapm_route *custom_map; 180 int num_routes; 181 int ret; 182 183 snd_soc_dapm_set_idle_bias(dapm, false); 184 185 switch (BYT_CHT_ES8316_MAP(quirk)) { 186 case BYT_CHT_ES8316_INTMIC_IN1_MAP: 187 default: 188 custom_map = byt_cht_es8316_intmic_in1_map; 189 num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in1_map); 190 break; 191 case BYT_CHT_ES8316_INTMIC_IN2_MAP: 192 custom_map = byt_cht_es8316_intmic_in2_map; 193 num_routes = ARRAY_SIZE(byt_cht_es8316_intmic_in2_map); 194 break; 195 } 196 ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); 197 if (ret) 198 return ret; 199 200 if (quirk & BYT_CHT_ES8316_SSP0) { 201 custom_map = byt_cht_es8316_ssp0_map; 202 num_routes = ARRAY_SIZE(byt_cht_es8316_ssp0_map); 203 } else { 204 custom_map = byt_cht_es8316_ssp2_map; 205 num_routes = ARRAY_SIZE(byt_cht_es8316_ssp2_map); 206 } 207 ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); 208 if (ret) 209 return ret; 210 211 /* 212 * The firmware might enable the clock at boot (this information 213 * may or may not be reflected in the enable clock register). 214 * To change the rate we must disable the clock first to cover these 215 * cases. Due to common clock framework restrictions that do not allow 216 * to disable a clock that has not been enabled, we need to enable 217 * the clock first. 218 */ 219 ret = clk_prepare_enable(priv->mclk); 220 if (!ret) 221 clk_disable_unprepare(priv->mclk); 222 223 ret = clk_set_rate(priv->mclk, 19200000); 224 if (ret) 225 dev_err(card->dev, "unable to set MCLK rate\n"); 226 227 ret = clk_prepare_enable(priv->mclk); 228 if (ret) 229 dev_err(card->dev, "unable to enable MCLK\n"); 230 231 ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_codec(runtime, 0), 0, 19200000, 232 SND_SOC_CLOCK_IN); 233 if (ret < 0) { 234 dev_err(card->dev, "can't set codec clock %d\n", ret); 235 return ret; 236 } 237 238 ret = snd_soc_card_jack_new_pins(card, "Headset", 239 SND_JACK_HEADSET | SND_JACK_BTN_0, 240 &priv->jack, byt_cht_es8316_jack_pins, 241 ARRAY_SIZE(byt_cht_es8316_jack_pins)); 242 if (ret) { 243 dev_err(card->dev, "jack creation failed %d\n", ret); 244 return ret; 245 } 246 247 snd_jack_set_key(priv->jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE); 248 snd_soc_component_set_jack(codec, &priv->jack, NULL); 249 250 return 0; 251} 252 253static int byt_cht_es8316_codec_fixup(struct snd_soc_pcm_runtime *rtd, 254 struct snd_pcm_hw_params *params) 255{ 256 struct snd_interval *rate = hw_param_interval(params, 257 SNDRV_PCM_HW_PARAM_RATE); 258 struct snd_interval *channels = hw_param_interval(params, 259 SNDRV_PCM_HW_PARAM_CHANNELS); 260 int ret, bits; 261 262 /* The DSP will convert the FE rate to 48k, stereo */ 263 rate->min = rate->max = 48000; 264 channels->min = channels->max = 2; 265 266 if (quirk & BYT_CHT_ES8316_SSP0) { 267 /* set SSP0 to 16-bit */ 268 params_set_format(params, SNDRV_PCM_FORMAT_S16_LE); 269 bits = 16; 270 } else { 271 /* set SSP2 to 24-bit */ 272 params_set_format(params, SNDRV_PCM_FORMAT_S24_LE); 273 bits = 24; 274 } 275 276 /* 277 * Default mode for SSP configuration is TDM 4 slot, override config 278 * with explicit setting to I2S 2ch 24-bit. The word length is set with 279 * dai_set_tdm_slot() since there is no other API exposed 280 */ 281 ret = snd_soc_dai_set_fmt(snd_soc_rtd_to_cpu(rtd, 0), 282 SND_SOC_DAIFMT_I2S | 283 SND_SOC_DAIFMT_NB_NF | 284 SND_SOC_DAIFMT_BP_FP 285 ); 286 if (ret < 0) { 287 dev_err(rtd->dev, "can't set format to I2S, err %d\n", ret); 288 return ret; 289 } 290 291 ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3, 2, bits); 292 if (ret < 0) { 293 dev_err(rtd->dev, "can't set I2S config, err %d\n", ret); 294 return ret; 295 } 296 297 return 0; 298} 299 300static int byt_cht_es8316_aif1_startup(struct snd_pcm_substream *substream) 301{ 302 return snd_pcm_hw_constraint_single(substream->runtime, 303 SNDRV_PCM_HW_PARAM_RATE, 48000); 304} 305 306static const struct snd_soc_ops byt_cht_es8316_aif1_ops = { 307 .startup = byt_cht_es8316_aif1_startup, 308}; 309 310SND_SOC_DAILINK_DEF(dummy, 311 DAILINK_COMP_ARRAY(COMP_DUMMY())); 312 313SND_SOC_DAILINK_DEF(media, 314 DAILINK_COMP_ARRAY(COMP_CPU("media-cpu-dai"))); 315 316SND_SOC_DAILINK_DEF(deepbuffer, 317 DAILINK_COMP_ARRAY(COMP_CPU("deepbuffer-cpu-dai"))); 318 319SND_SOC_DAILINK_DEF(ssp2_port, 320 DAILINK_COMP_ARRAY(COMP_CPU("ssp2-port"))); 321SND_SOC_DAILINK_DEF(ssp2_codec, 322 DAILINK_COMP_ARRAY(COMP_CODEC("i2c-ESSX8316:00", "ES8316 HiFi"))); 323 324SND_SOC_DAILINK_DEF(platform, 325 DAILINK_COMP_ARRAY(COMP_PLATFORM("sst-mfld-platform"))); 326 327static struct snd_soc_dai_link byt_cht_es8316_dais[] = { 328 [MERR_DPCM_AUDIO] = { 329 .name = "Audio Port", 330 .stream_name = "Audio", 331 .nonatomic = true, 332 .dynamic = 1, 333 .ops = &byt_cht_es8316_aif1_ops, 334 SND_SOC_DAILINK_REG(media, dummy, platform), 335 }, 336 337 [MERR_DPCM_DEEP_BUFFER] = { 338 .name = "Deep-Buffer Audio Port", 339 .stream_name = "Deep-Buffer Audio", 340 .nonatomic = true, 341 .dynamic = 1, 342 .playback_only = 1, 343 .ops = &byt_cht_es8316_aif1_ops, 344 SND_SOC_DAILINK_REG(deepbuffer, dummy, platform), 345 }, 346 347 /* back ends */ 348 { 349 .name = "SSP2-Codec", 350 .id = 0, 351 .no_pcm = 1, 352 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF 353 | SND_SOC_DAIFMT_CBC_CFC, 354 .be_hw_params_fixup = byt_cht_es8316_codec_fixup, 355 .init = byt_cht_es8316_init, 356 SND_SOC_DAILINK_REG(ssp2_port, ssp2_codec, platform), 357 }, 358}; 359 360 361/* SoC card */ 362static char codec_name[SND_ACPI_I2C_ID_LEN]; 363#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) 364static char long_name[50]; /* = "bytcht-es8316-*-spk-*-mic" */ 365#endif 366static char components_string[32]; /* = "cfg-spk:* cfg-mic:* */ 367 368static int byt_cht_es8316_suspend(struct snd_soc_card *card) 369{ 370 struct snd_soc_component *component; 371 372 for_each_card_components(card, component) { 373 if (!strcmp(component->name, codec_name)) { 374 dev_dbg(component->dev, "disabling jack detect before suspend\n"); 375 snd_soc_component_set_jack(component, NULL, NULL); 376 break; 377 } 378 } 379 380 return 0; 381} 382 383static int byt_cht_es8316_resume(struct snd_soc_card *card) 384{ 385 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 386 struct snd_soc_component *component; 387 388 for_each_card_components(card, component) { 389 if (!strcmp(component->name, codec_name)) { 390 dev_dbg(component->dev, "re-enabling jack detect after resume\n"); 391 snd_soc_component_set_jack(component, &priv->jack, NULL); 392 break; 393 } 394 } 395 396 /* 397 * Some Cherry Trail boards with an ES8316 codec have a bug in their 398 * ACPI tables where the MSSL1680 touchscreen's _PS0 and _PS3 methods 399 * wrongly also set the speaker-enable GPIO to 1/0. Testing has shown 400 * that this really is a bug and the GPIO has no influence on the 401 * touchscreen at all. 402 * 403 * The silead.c touchscreen driver does not support runtime suspend, so 404 * the GPIO can only be changed underneath us during a system suspend. 405 * This resume() function runs from a pm complete() callback, and thus 406 * is guaranteed to run after the touchscreen driver/ACPI-subsys has 407 * brought the touchscreen back up again (and thus changed the GPIO). 408 * 409 * So to work around this we pass GPIOD_FLAGS_BIT_NONEXCLUSIVE when 410 * requesting the GPIO and we set its value here to undo any changes 411 * done by the touchscreen's broken _PS0 ACPI method. 412 */ 413 gpiod_set_value_cansleep(priv->speaker_en_gpio, priv->speaker_en); 414 415 return 0; 416} 417 418/* use space before codec name to simplify card ID, and simplify driver name */ 419#define SOF_CARD_NAME "bytcht es8316" /* card name will be 'sof-bytcht es8316' */ 420#define SOF_DRIVER_NAME "SOF" 421 422#define CARD_NAME "bytcht-es8316" 423#define DRIVER_NAME NULL /* card name will be used for driver name */ 424 425static struct snd_soc_card byt_cht_es8316_card = { 426 .owner = THIS_MODULE, 427 .dai_link = byt_cht_es8316_dais, 428 .num_links = ARRAY_SIZE(byt_cht_es8316_dais), 429 .dapm_widgets = byt_cht_es8316_widgets, 430 .num_dapm_widgets = ARRAY_SIZE(byt_cht_es8316_widgets), 431 .dapm_routes = byt_cht_es8316_audio_map, 432 .num_dapm_routes = ARRAY_SIZE(byt_cht_es8316_audio_map), 433 .controls = byt_cht_es8316_controls, 434 .num_controls = ARRAY_SIZE(byt_cht_es8316_controls), 435 .fully_routed = true, 436 .suspend_pre = byt_cht_es8316_suspend, 437 .resume_post = byt_cht_es8316_resume, 438}; 439 440static const struct acpi_gpio_params first_gpio = { 0, 0, false }; 441 442static const struct acpi_gpio_mapping byt_cht_es8316_gpios[] = { 443 { "speaker-enable-gpios", &first_gpio, 1 }, 444 { }, 445}; 446 447/* Please keep this list alphabetically sorted */ 448static const struct dmi_system_id byt_cht_es8316_quirk_table[] = { 449 { /* Irbis NB41 */ 450 .matches = { 451 DMI_MATCH(DMI_SYS_VENDOR, "IRBIS"), 452 DMI_MATCH(DMI_PRODUCT_NAME, "NB41"), 453 }, 454 .driver_data = (void *)(BYT_CHT_ES8316_SSP0 455 | BYT_CHT_ES8316_INTMIC_IN2_MAP 456 | BYT_CHT_ES8316_JD_INVERTED), 457 }, 458 { /* Nanote UMPC-01 */ 459 .matches = { 460 DMI_MATCH(DMI_SYS_VENDOR, "RWC CO.,LTD"), 461 DMI_MATCH(DMI_PRODUCT_NAME, "UMPC-01"), 462 }, 463 .driver_data = (void *)BYT_CHT_ES8316_INTMIC_IN1_MAP, 464 }, 465 { /* Teclast X98 Plus II */ 466 .matches = { 467 DMI_MATCH(DMI_SYS_VENDOR, "TECLAST"), 468 DMI_MATCH(DMI_PRODUCT_NAME, "X98 Plus II"), 469 }, 470 .driver_data = (void *)(BYT_CHT_ES8316_INTMIC_IN1_MAP 471 | BYT_CHT_ES8316_JD_INVERTED), 472 }, 473 {} 474}; 475 476static int byt_cht_es8316_get_quirks_from_dsm(struct byt_cht_es8316_private *priv, 477 bool is_bytcr) 478{ 479 int ret, val1, val2, dsm_quirk = 0; 480 481 if (is_bytcr) 482 dsm_quirk |= BYT_CHT_ES8316_SSP0; 483 484 ret = es83xx_dsm(priv->codec_dev, PLATFORM_MAINMIC_TYPE_ARG, &val1); 485 if (ret < 0) 486 return ret; 487 488 ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPMIC_TYPE_ARG, &val2); 489 if (ret < 0) 490 return ret; 491 492 if (val1 == PLATFORM_MIC_AMIC_LIN1RIN1 && val2 == PLATFORM_MIC_AMIC_LIN2RIN2) { 493 dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN1_MAP; 494 } else if (val1 == PLATFORM_MIC_AMIC_LIN2RIN2 && val2 == PLATFORM_MIC_AMIC_LIN1RIN1) { 495 dsm_quirk |= BYT_CHT_ES8316_INTMIC_IN2_MAP; 496 } else { 497 dev_warn(priv->codec_dev, "Unknown mic settings mainmic 0x%02x hpmic 0x%02x\n", 498 val1, val2); 499 return -EINVAL; 500 } 501 502 ret = es83xx_dsm(priv->codec_dev, PLATFORM_SPK_TYPE_ARG, &val1); 503 if (ret < 0) 504 return ret; 505 506 switch (val1) { 507 case PLATFORM_SPK_MONO: 508 dsm_quirk |= BYT_CHT_ES8316_MONO_SPEAKER; 509 break; 510 case PLATFORM_SPK_STEREO: 511 break; 512 default: 513 dev_warn(priv->codec_dev, "Unknown speaker setting 0x%02x\n", val1); 514 return -EINVAL; 515 } 516 517 ret = es83xx_dsm(priv->codec_dev, PLATFORM_HPDET_INV_ARG, &val1); 518 if (ret < 0) 519 return ret; 520 521 switch (val1) { 522 case PLATFORM_HPDET_NORMAL: 523 break; 524 case PLATFORM_HPDET_INVERTED: 525 dsm_quirk |= BYT_CHT_ES8316_JD_INVERTED; 526 break; 527 default: 528 dev_warn(priv->codec_dev, "Unknown hpdet-inv setting 0x%02x\n", val1); 529 return -EINVAL; 530 } 531 532 quirk = dsm_quirk; 533 return 0; 534} 535 536static int snd_byt_cht_es8316_mc_probe(struct platform_device *pdev) 537{ 538 struct device *dev = &pdev->dev; 539 static const char * const mic_name[] = { "in1", "in2" }; 540 struct snd_soc_acpi_mach *mach = dev_get_platdata(dev); 541 struct property_entry props[MAX_NO_PROPS] = {}; 542 struct byt_cht_es8316_private *priv; 543 const struct dmi_system_id *dmi_id; 544 struct fwnode_handle *fwnode; 545 bool sof_parent, is_bytcr; 546 const char *platform_name; 547 struct acpi_device *adev; 548 struct device *codec_dev; 549 unsigned int cnt = 0; 550 int dai_index = 0; 551 int i; 552 int ret = 0; 553 554 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 555 if (!priv) 556 return -ENOMEM; 557 558 /* fix index of codec dai */ 559 for (i = 0; i < ARRAY_SIZE(byt_cht_es8316_dais); i++) { 560 if (byt_cht_es8316_dais[i].num_codecs && 561 !strcmp(byt_cht_es8316_dais[i].codecs->name, 562 "i2c-ESSX8316:00")) { 563 dai_index = i; 564 break; 565 } 566 } 567 568 /* fixup codec name based on HID */ 569 adev = acpi_dev_get_first_match_dev(mach->id, NULL, -1); 570 if (adev) { 571 snprintf(codec_name, sizeof(codec_name), 572 "i2c-%s", acpi_dev_name(adev)); 573 byt_cht_es8316_dais[dai_index].codecs->name = codec_name; 574 } else { 575 dev_err(dev, "Error cannot find '%s' dev\n", mach->id); 576 return -ENOENT; 577 } 578 579 codec_dev = acpi_get_first_physical_node(adev); 580 acpi_dev_put(adev); 581 if (!codec_dev) 582 return -EPROBE_DEFER; 583 priv->codec_dev = get_device(codec_dev); 584 585 /* override platform name, if required */ 586 byt_cht_es8316_card.dev = dev; 587 platform_name = mach->mach_params.platform; 588 589 ret = snd_soc_fixup_dai_links_platform_name(&byt_cht_es8316_card, 590 platform_name); 591 if (ret) { 592 put_device(codec_dev); 593 return ret; 594 } 595 596 es83xx_dsm_dump(priv->codec_dev); 597 598 /* Check for BYTCR or other platform and setup quirks */ 599 is_bytcr = soc_intel_is_byt() && mach->mach_params.acpi_ipc_irq_index == 0; 600 dmi_id = dmi_first_match(byt_cht_es8316_quirk_table); 601 if (dmi_id) { 602 quirk = (unsigned long)dmi_id->driver_data; 603 } else if (!byt_cht_es8316_get_quirks_from_dsm(priv, is_bytcr)) { 604 dev_info(dev, "Using ACPI DSM info for quirks\n"); 605 } else if (is_bytcr) { 606 /* On BYTCR default to SSP0, internal-mic-in2-map, mono-spk */ 607 quirk = BYT_CHT_ES8316_SSP0 | BYT_CHT_ES8316_INTMIC_IN2_MAP | 608 BYT_CHT_ES8316_MONO_SPEAKER; 609 } else { 610 /* Others default to internal-mic-in1-map, mono-speaker */ 611 quirk = BYT_CHT_ES8316_INTMIC_IN1_MAP | 612 BYT_CHT_ES8316_MONO_SPEAKER; 613 } 614 if (quirk_override != -1) { 615 dev_info(dev, "Overriding quirk 0x%lx => 0x%x\n", 616 quirk, quirk_override); 617 quirk = quirk_override; 618 } 619 log_quirks(dev); 620 621 if (quirk & BYT_CHT_ES8316_SSP0) 622 byt_cht_es8316_dais[dai_index].cpus->dai_name = "ssp0-port"; 623 624 /* get the clock */ 625 priv->mclk = devm_clk_get(dev, "pmc_plt_clk_3"); 626 if (IS_ERR(priv->mclk)) { 627 put_device(codec_dev); 628 return dev_err_probe(dev, PTR_ERR(priv->mclk), "clk_get pmc_plt_clk_3 failed\n"); 629 } 630 631 if (quirk & BYT_CHT_ES8316_JD_INVERTED) 632 props[cnt++] = PROPERTY_ENTRY_BOOL("everest,jack-detect-inverted"); 633 634 if (cnt) { 635 fwnode = fwnode_create_software_node(props, NULL); 636 if (IS_ERR(fwnode)) { 637 put_device(codec_dev); 638 return PTR_ERR(fwnode); 639 } 640 641 ret = device_add_software_node(codec_dev, to_software_node(fwnode)); 642 643 fwnode_handle_put(fwnode); 644 645 if (ret) { 646 put_device(codec_dev); 647 return ret; 648 } 649 } 650 651 /* get speaker enable GPIO */ 652 devm_acpi_dev_add_driver_gpios(codec_dev, byt_cht_es8316_gpios); 653 priv->speaker_en_gpio = 654 gpiod_get_optional(codec_dev, "speaker-enable", 655 /* see comment in byt_cht_es8316_resume() */ 656 GPIOD_OUT_LOW | GPIOD_FLAGS_BIT_NONEXCLUSIVE); 657 if (IS_ERR(priv->speaker_en_gpio)) { 658 ret = dev_err_probe(dev, PTR_ERR(priv->speaker_en_gpio), 659 "get speaker GPIO failed\n"); 660 goto err_put_codec; 661 } 662 663 snprintf(components_string, sizeof(components_string), 664 "cfg-spk:%s cfg-mic:%s", 665 (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "1" : "2", 666 mic_name[BYT_CHT_ES8316_MAP(quirk)]); 667 byt_cht_es8316_card.components = components_string; 668#if !IS_ENABLED(CONFIG_SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES) 669 snprintf(long_name, sizeof(long_name), "bytcht-es8316-%s-spk-%s-mic", 670 (quirk & BYT_CHT_ES8316_MONO_SPEAKER) ? "mono" : "stereo", 671 mic_name[BYT_CHT_ES8316_MAP(quirk)]); 672 byt_cht_es8316_card.long_name = long_name; 673#endif 674 675 sof_parent = snd_soc_acpi_sof_parent(dev); 676 677 /* set card and driver name */ 678 if (sof_parent) { 679 byt_cht_es8316_card.name = SOF_CARD_NAME; 680 byt_cht_es8316_card.driver_name = SOF_DRIVER_NAME; 681 } else { 682 byt_cht_es8316_card.name = CARD_NAME; 683 byt_cht_es8316_card.driver_name = DRIVER_NAME; 684 } 685 686 /* set pm ops */ 687 if (sof_parent) 688 dev->driver->pm = &snd_soc_pm_ops; 689 690 /* register the soc card */ 691 snd_soc_card_set_drvdata(&byt_cht_es8316_card, priv); 692 693 ret = devm_snd_soc_register_card(dev, &byt_cht_es8316_card); 694 if (ret) { 695 gpiod_put(priv->speaker_en_gpio); 696 dev_err(dev, "snd_soc_register_card failed: %d\n", ret); 697 goto err_put_codec; 698 } 699 platform_set_drvdata(pdev, &byt_cht_es8316_card); 700 return 0; 701 702err_put_codec: 703 device_remove_software_node(priv->codec_dev); 704 put_device(priv->codec_dev); 705 return ret; 706} 707 708static void snd_byt_cht_es8316_mc_remove(struct platform_device *pdev) 709{ 710 struct snd_soc_card *card = platform_get_drvdata(pdev); 711 struct byt_cht_es8316_private *priv = snd_soc_card_get_drvdata(card); 712 713 gpiod_put(priv->speaker_en_gpio); 714 device_remove_software_node(priv->codec_dev); 715 put_device(priv->codec_dev); 716} 717 718static struct platform_driver snd_byt_cht_es8316_mc_driver = { 719 .driver = { 720 .name = "bytcht_es8316", 721 }, 722 .probe = snd_byt_cht_es8316_mc_probe, 723 .remove = snd_byt_cht_es8316_mc_remove, 724}; 725 726module_platform_driver(snd_byt_cht_es8316_mc_driver); 727MODULE_DESCRIPTION("ASoC Intel(R) Baytrail/Cherrytrail Machine driver"); 728MODULE_AUTHOR("David Yang <yangxiaohua@everest-semi.com>"); 729MODULE_LICENSE("GPL v2"); 730MODULE_ALIAS("platform:bytcht_es8316");
~/
Read-only file preview.