1 // SPDX-License-Identifier: GPL-2.0+ 2 #include <linux/extcon.h> 3 #include <linux/iio/consumer.h> 4 #include <linux/input-event-codes.h> 5 #include <linux/mfd/wm8994/registers.h> 6 #include <linux/module.h> 7 #include <linux/of.h> 8 #include <linux/of_device.h> 9 #include <linux/of_gpio.h> 10 #include <linux/regulator/consumer.h> 11 #include <sound/jack.h> 12 #include <sound/pcm_params.h> 13 #include <sound/soc.h> 14 15 #include "i2s.h" 16 #include "../codecs/wm8994.h" 17 18 #define ARIES_MCLK1_FREQ 24000000 19 20 struct aries_wm8994_variant { 21 unsigned int modem_dai_fmt; 22 bool has_fm_radio; 23 }; 24 25 struct aries_wm8994_data { 26 struct extcon_dev *usb_extcon; 27 struct regulator *reg_main_micbias; 28 struct regulator *reg_headset_micbias; 29 struct gpio_desc *gpio_headset_detect; 30 struct gpio_desc *gpio_headset_key; 31 struct gpio_desc *gpio_earpath_sel; 32 struct iio_channel *adc; 33 const struct aries_wm8994_variant *variant; 34 }; 35 36 /* USB dock */ 37 static struct snd_soc_jack aries_dock; 38 39 static struct snd_soc_jack_pin dock_pins[] = { 40 { 41 .pin = "LINE", 42 .mask = SND_JACK_LINEOUT, 43 }, 44 }; 45 46 static int aries_extcon_notifier(struct notifier_block *this, 47 unsigned long connected, void *_cmd) 48 { 49 if (connected) 50 snd_soc_jack_report(&aries_dock, SND_JACK_LINEOUT, 51 SND_JACK_LINEOUT); 52 else 53 snd_soc_jack_report(&aries_dock, 0, SND_JACK_LINEOUT); 54 55 return NOTIFY_DONE; 56 } 57 58 static struct notifier_block aries_extcon_notifier_block = { 59 .notifier_call = aries_extcon_notifier, 60 }; 61 62 /* Headset jack */ 63 static struct snd_soc_jack aries_headset; 64 65 static struct snd_soc_jack_pin jack_pins[] = { 66 { 67 .pin = "HP", 68 .mask = SND_JACK_HEADPHONE, 69 }, { 70 .pin = "Headset Mic", 71 .mask = SND_JACK_MICROPHONE, 72 }, 73 }; 74 75 static struct snd_soc_jack_zone headset_zones[] = { 76 { 77 .min_mv = 0, 78 .max_mv = 241, 79 .jack_type = SND_JACK_HEADPHONE, 80 }, { 81 .min_mv = 242, 82 .max_mv = 2980, 83 .jack_type = SND_JACK_HEADSET, 84 }, { 85 .min_mv = 2981, 86 .max_mv = UINT_MAX, 87 .jack_type = SND_JACK_HEADPHONE, 88 }, 89 }; 90 91 static irqreturn_t headset_det_irq_thread(int irq, void *data) 92 { 93 struct aries_wm8994_data *priv = (struct aries_wm8994_data *) data; 94 int ret = 0; 95 int time_left_ms = 300; 96 int adc; 97 98 while (time_left_ms > 0) { 99 if (!gpiod_get_value(priv->gpio_headset_detect)) { 100 snd_soc_jack_report(&aries_headset, 0, 101 SND_JACK_HEADSET); 102 gpiod_set_value(priv->gpio_earpath_sel, 0); 103 return IRQ_HANDLED; 104 } 105 msleep(20); 106 time_left_ms -= 20; 107 } 108 109 /* Temporarily enable micbias and earpath selector */ 110 ret = regulator_enable(priv->reg_headset_micbias); 111 if (ret) 112 pr_err("%s failed to enable micbias: %d", __func__, ret); 113 114 gpiod_set_value(priv->gpio_earpath_sel, 1); 115 116 ret = iio_read_channel_processed(priv->adc, &adc); 117 if (ret < 0) { 118 /* failed to read ADC, so assume headphone */ 119 pr_err("%s failed to read ADC, assuming headphones", __func__); 120 snd_soc_jack_report(&aries_headset, SND_JACK_HEADPHONE, 121 SND_JACK_HEADSET); 122 } else { 123 snd_soc_jack_report(&aries_headset, 124 snd_soc_jack_get_type(&aries_headset, adc), 125 SND_JACK_HEADSET); 126 } 127 128 ret = regulator_disable(priv->reg_headset_micbias); 129 if (ret) 130 pr_err("%s failed disable micbias: %d", __func__, ret); 131 132 /* Disable earpath selector when no mic connected */ 133 if (!(aries_headset.status & SND_JACK_MICROPHONE)) 134 gpiod_set_value(priv->gpio_earpath_sel, 0); 135 136 return IRQ_HANDLED; 137 } 138 139 static int headset_button_check(void *data) 140 { 141 struct aries_wm8994_data *priv = (struct aries_wm8994_data *) data; 142 143 /* Filter out keypresses when 4 pole jack not detected */ 144 if (gpiod_get_value_cansleep(priv->gpio_headset_key) && 145 aries_headset.status & SND_JACK_MICROPHONE) 146 return SND_JACK_BTN_0; 147 148 return 0; 149 } 150 151 static struct snd_soc_jack_gpio headset_button_gpio[] = { 152 { 153 .name = "Media Button", 154 .report = SND_JACK_BTN_0, 155 .debounce_time = 30, 156 .jack_status_check = headset_button_check, 157 }, 158 }; 159 160 static int aries_spk_cfg(struct snd_soc_dapm_widget *w, 161 struct snd_kcontrol *kcontrol, int event) 162 { 163 struct snd_soc_card *card = w->dapm->card; 164 struct snd_soc_pcm_runtime *rtd; 165 struct snd_soc_component *component; 166 int ret = 0; 167 168 rtd = snd_soc_get_pcm_runtime(card, &card->dai_link[0]); 169 component = asoc_rtd_to_codec(rtd, 0)->component; 170 171 /** 172 * We have an odd setup - the SPKMODE pin is pulled up so 173 * we only have access to the left side SPK configs, 174 * but SPKOUTR isn't bridged so when playing back in 175 * stereo, we only get the left hand channel. The only 176 * option we're left with is to force the AIF into mono 177 * mode. 178 */ 179 switch (event) { 180 case SND_SOC_DAPM_POST_PMU: 181 ret = snd_soc_component_update_bits(component, 182 WM8994_AIF1_DAC1_FILTERS_1, 183 WM8994_AIF1DAC1_MONO, WM8994_AIF1DAC1_MONO); 184 break; 185 case SND_SOC_DAPM_PRE_PMD: 186 ret = snd_soc_component_update_bits(component, 187 WM8994_AIF1_DAC1_FILTERS_1, 188 WM8994_AIF1DAC1_MONO, 0); 189 break; 190 } 191 192 return ret; 193 } 194 195 static int aries_main_bias(struct snd_soc_dapm_widget *w, 196 struct snd_kcontrol *kcontrol, int event) 197 { 198 struct snd_soc_card *card = w->dapm->card; 199 struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card); 200 int ret = 0; 201 202 switch (event) { 203 case SND_SOC_DAPM_PRE_PMU: 204 ret = regulator_enable(priv->reg_main_micbias); 205 break; 206 case SND_SOC_DAPM_POST_PMD: 207 ret = regulator_disable(priv->reg_main_micbias); 208 break; 209 } 210 211 return ret; 212 } 213 214 static int aries_headset_bias(struct snd_soc_dapm_widget *w, 215 struct snd_kcontrol *kcontrol, int event) 216 { 217 struct snd_soc_card *card = w->dapm->card; 218 struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card); 219 int ret = 0; 220 221 switch (event) { 222 case SND_SOC_DAPM_PRE_PMU: 223 ret = regulator_enable(priv->reg_headset_micbias); 224 break; 225 case SND_SOC_DAPM_POST_PMD: 226 ret = regulator_disable(priv->reg_headset_micbias); 227 break; 228 } 229 230 return ret; 231 } 232 233 static const struct snd_kcontrol_new aries_controls[] = { 234 SOC_DAPM_PIN_SWITCH("Modem In"), 235 SOC_DAPM_PIN_SWITCH("Modem Out"), 236 }; 237 238 static const struct snd_soc_dapm_widget aries_dapm_widgets[] = { 239 SND_SOC_DAPM_HP("HP", NULL), 240 241 SND_SOC_DAPM_SPK("SPK", aries_spk_cfg), 242 SND_SOC_DAPM_SPK("RCV", NULL), 243 244 SND_SOC_DAPM_LINE("LINE", NULL), 245 246 SND_SOC_DAPM_MIC("Main Mic", aries_main_bias), 247 SND_SOC_DAPM_MIC("Headset Mic", aries_headset_bias), 248 249 SND_SOC_DAPM_MIC("Bluetooth Mic", NULL), 250 SND_SOC_DAPM_SPK("Bluetooth SPK", NULL), 251 252 SND_SOC_DAPM_LINE("Modem In", NULL), 253 SND_SOC_DAPM_LINE("Modem Out", NULL), 254 255 /* This must be last as it is conditionally not used */ 256 SND_SOC_DAPM_LINE("FM In", NULL), 257 }; 258 259 static int aries_hw_params(struct snd_pcm_substream *substream, 260 struct snd_pcm_hw_params *params) 261 { 262 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 263 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 264 unsigned int pll_out; 265 int ret; 266 267 /* AIF1CLK should be >=3MHz for optimal performance */ 268 if (params_width(params) == 24) 269 pll_out = params_rate(params) * 384; 270 else if (params_rate(params) == 8000 || params_rate(params) == 11025) 271 pll_out = params_rate(params) * 512; 272 else 273 pll_out = params_rate(params) * 256; 274 275 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, 276 ARIES_MCLK1_FREQ, pll_out); 277 if (ret < 0) 278 return ret; 279 280 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL1, 281 pll_out, SND_SOC_CLOCK_IN); 282 if (ret < 0) 283 return ret; 284 285 return 0; 286 } 287 288 static int aries_hw_free(struct snd_pcm_substream *substream) 289 { 290 struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 291 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 292 int ret; 293 294 /* Switch sysclk to MCLK1 */ 295 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, 296 ARIES_MCLK1_FREQ, SND_SOC_CLOCK_IN); 297 if (ret < 0) 298 return ret; 299 300 /* Stop PLL */ 301 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL1, WM8994_FLL_SRC_MCLK1, 302 ARIES_MCLK1_FREQ, 0); 303 if (ret < 0) 304 return ret; 305 306 return 0; 307 } 308 309 /* 310 * Main DAI operations 311 */ 312 static const struct snd_soc_ops aries_ops = { 313 .hw_params = aries_hw_params, 314 .hw_free = aries_hw_free, 315 }; 316 317 static int aries_baseband_init(struct snd_soc_pcm_runtime *rtd) 318 { 319 struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0); 320 unsigned int pll_out; 321 int ret; 322 323 pll_out = 8000 * 512; 324 325 /* Set the codec FLL */ 326 ret = snd_soc_dai_set_pll(codec_dai, WM8994_FLL2, WM8994_FLL_SRC_MCLK1, 327 ARIES_MCLK1_FREQ, pll_out); 328 if (ret < 0) 329 return ret; 330 331 /* Set the codec system clock */ 332 ret = snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_FLL2, 333 pll_out, SND_SOC_CLOCK_IN); 334 if (ret < 0) 335 return ret; 336 337 return 0; 338 } 339 340 static int aries_late_probe(struct snd_soc_card *card) 341 { 342 struct aries_wm8994_data *priv = snd_soc_card_get_drvdata(card); 343 int ret, irq; 344 345 ret = snd_soc_card_jack_new_pins(card, "Dock", SND_JACK_LINEOUT, 346 &aries_dock, dock_pins, ARRAY_SIZE(dock_pins)); 347 if (ret) 348 return ret; 349 350 ret = devm_extcon_register_notifier(card->dev, 351 priv->usb_extcon, EXTCON_JACK_LINE_OUT, 352 &aries_extcon_notifier_block); 353 if (ret) 354 return ret; 355 356 if (extcon_get_state(priv->usb_extcon, 357 EXTCON_JACK_LINE_OUT) > 0) 358 snd_soc_jack_report(&aries_dock, SND_JACK_LINEOUT, 359 SND_JACK_LINEOUT); 360 else 361 snd_soc_jack_report(&aries_dock, 0, SND_JACK_LINEOUT); 362 363 ret = snd_soc_card_jack_new_pins(card, "Headset", 364 SND_JACK_HEADSET | SND_JACK_BTN_0, 365 &aries_headset, 366 jack_pins, ARRAY_SIZE(jack_pins)); 367 if (ret) 368 return ret; 369 370 ret = snd_soc_jack_add_zones(&aries_headset, ARRAY_SIZE(headset_zones), 371 headset_zones); 372 if (ret) 373 return ret; 374 375 irq = gpiod_to_irq(priv->gpio_headset_detect); 376 if (irq < 0) { 377 dev_err(card->dev, "Failed to map headset detect gpio to irq"); 378 return -EINVAL; 379 } 380 381 ret = devm_request_threaded_irq(card->dev, irq, NULL, 382 headset_det_irq_thread, 383 IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 384 IRQF_ONESHOT, "headset_detect", priv); 385 if (ret) { 386 dev_err(card->dev, "Failed to request headset detect irq"); 387 return ret; 388 } 389 390 headset_button_gpio[0].data = priv; 391 headset_button_gpio[0].desc = priv->gpio_headset_key; 392 393 snd_jack_set_key(aries_headset.jack, SND_JACK_BTN_0, KEY_MEDIA); 394 395 return snd_soc_jack_add_gpios(&aries_headset, 396 ARRAY_SIZE(headset_button_gpio), headset_button_gpio); 397 } 398 399 static const struct snd_soc_pcm_stream baseband_params = { 400 .formats = SNDRV_PCM_FMTBIT_S16_LE, 401 .rate_min = 8000, 402 .rate_max = 8000, 403 .channels_min = 1, 404 .channels_max = 1, 405 }; 406 407 static const struct snd_soc_pcm_stream bluetooth_params = { 408 .formats = SNDRV_PCM_FMTBIT_S16_LE, 409 .rate_min = 8000, 410 .rate_max = 8000, 411 .channels_min = 1, 412 .channels_max = 2, 413 }; 414 415 static const struct snd_soc_dapm_widget aries_modem_widgets[] = { 416 SND_SOC_DAPM_INPUT("Modem RX"), 417 SND_SOC_DAPM_OUTPUT("Modem TX"), 418 }; 419 420 static const struct snd_soc_dapm_route aries_modem_routes[] = { 421 { "Modem Capture", NULL, "Modem RX" }, 422 { "Modem TX", NULL, "Modem Playback" }, 423 }; 424 425 static const struct snd_soc_component_driver aries_component = { 426 .name = "aries-audio", 427 .dapm_widgets = aries_modem_widgets, 428 .num_dapm_widgets = ARRAY_SIZE(aries_modem_widgets), 429 .dapm_routes = aries_modem_routes, 430 .num_dapm_routes = ARRAY_SIZE(aries_modem_routes), 431 .idle_bias_on = 1, 432 .use_pmdown_time = 1, 433 .endianness = 1, 434 }; 435 436 static struct snd_soc_dai_driver aries_ext_dai[] = { 437 { 438 .name = "Voice call", 439 .playback = { 440 .stream_name = "Modem Playback", 441 .channels_min = 1, 442 .channels_max = 1, 443 .rate_min = 8000, 444 .rate_max = 8000, 445 .rates = SNDRV_PCM_RATE_8000, 446 .formats = SNDRV_PCM_FMTBIT_S16_LE, 447 }, 448 .capture = { 449 .stream_name = "Modem Capture", 450 .channels_min = 1, 451 .channels_max = 1, 452 .rate_min = 8000, 453 .rate_max = 8000, 454 .rates = SNDRV_PCM_RATE_8000, 455 .formats = SNDRV_PCM_FMTBIT_S16_LE, 456 }, 457 }, 458 }; 459 460 SND_SOC_DAILINK_DEFS(aif1, 461 DAILINK_COMP_ARRAY(COMP_CPU(SAMSUNG_I2S_DAI)), 462 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif1")), 463 DAILINK_COMP_ARRAY(COMP_EMPTY())); 464 465 SND_SOC_DAILINK_DEFS(baseband, 466 DAILINK_COMP_ARRAY(COMP_CPU("Voice call")), 467 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif2"))); 468 469 SND_SOC_DAILINK_DEFS(bluetooth, 470 DAILINK_COMP_ARRAY(COMP_CPU("bt-sco-pcm")), 471 DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "wm8994-aif3"))); 472 473 static struct snd_soc_dai_link aries_dai[] = { 474 { 475 .name = "WM8994 AIF1", 476 .stream_name = "HiFi", 477 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | 478 SND_SOC_DAIFMT_CBM_CFM, 479 .ops = &aries_ops, 480 SND_SOC_DAILINK_REG(aif1), 481 }, 482 { 483 .name = "WM8994 AIF2", 484 .stream_name = "Baseband", 485 .init = &aries_baseband_init, 486 .c2c_params = &baseband_params, 487 .num_c2c_params = 1, 488 .ignore_suspend = 1, 489 SND_SOC_DAILINK_REG(baseband), 490 }, 491 { 492 .name = "WM8994 AIF3", 493 .stream_name = "Bluetooth", 494 .c2c_params = &bluetooth_params, 495 .num_c2c_params = 1, 496 .ignore_suspend = 1, 497 SND_SOC_DAILINK_REG(bluetooth), 498 }, 499 }; 500 501 static struct snd_soc_card aries_card = { 502 .name = "ARIES", 503 .owner = THIS_MODULE, 504 .dai_link = aries_dai, 505 .num_links = ARRAY_SIZE(aries_dai), 506 .controls = aries_controls, 507 .num_controls = ARRAY_SIZE(aries_controls), 508 .dapm_widgets = aries_dapm_widgets, 509 .num_dapm_widgets = ARRAY_SIZE(aries_dapm_widgets), 510 .late_probe = aries_late_probe, 511 }; 512 513 static const struct aries_wm8994_variant fascinate4g_variant = { 514 .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS 515 | SND_SOC_DAIFMT_IB_NF, 516 .has_fm_radio = false, 517 }; 518 519 static const struct aries_wm8994_variant aries_variant = { 520 .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM 521 | SND_SOC_DAIFMT_IB_NF, 522 .has_fm_radio = true, 523 }; 524 525 static const struct of_device_id samsung_wm8994_of_match[] = { 526 { 527 .compatible = "samsung,fascinate4g-wm8994", 528 .data = &fascinate4g_variant, 529 }, 530 { 531 .compatible = "samsung,aries-wm8994", 532 .data = &aries_variant, 533 }, 534 { /* sentinel */ }, 535 }; 536 MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); 537 538 static int aries_audio_probe(struct platform_device *pdev) 539 { 540 struct device_node *np = pdev->dev.of_node; 541 struct device_node *cpu, *codec, *extcon_np; 542 struct device *dev = &pdev->dev; 543 struct snd_soc_card *card = &aries_card; 544 struct aries_wm8994_data *priv; 545 struct snd_soc_dai_link *dai_link; 546 const struct of_device_id *match; 547 enum iio_chan_type channel_type; 548 int ret, i; 549 550 if (!np) 551 return -EINVAL; 552 553 card->dev = dev; 554 555 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 556 if (!priv) 557 return -ENOMEM; 558 559 snd_soc_card_set_drvdata(card, priv); 560 561 match = of_match_node(samsung_wm8994_of_match, np); 562 priv->variant = match->data; 563 564 /* Remove FM widget if not present */ 565 if (!priv->variant->has_fm_radio) 566 card->num_dapm_widgets--; 567 568 priv->reg_main_micbias = devm_regulator_get(dev, "main-micbias"); 569 if (IS_ERR(priv->reg_main_micbias)) { 570 dev_err(dev, "Failed to get main micbias regulator\n"); 571 return PTR_ERR(priv->reg_main_micbias); 572 } 573 574 priv->reg_headset_micbias = devm_regulator_get(dev, "headset-micbias"); 575 if (IS_ERR(priv->reg_headset_micbias)) { 576 dev_err(dev, "Failed to get headset micbias regulator\n"); 577 return PTR_ERR(priv->reg_headset_micbias); 578 } 579 580 priv->gpio_earpath_sel = devm_gpiod_get(dev, "earpath-sel", 581 GPIOD_OUT_LOW); 582 if (IS_ERR(priv->gpio_earpath_sel)) { 583 dev_err(dev, "Failed to get earpath selector gpio"); 584 return PTR_ERR(priv->gpio_earpath_sel); 585 } 586 587 extcon_np = of_parse_phandle(np, "extcon", 0); 588 priv->usb_extcon = extcon_find_edev_by_node(extcon_np); 589 of_node_put(extcon_np); 590 if (IS_ERR(priv->usb_extcon)) 591 return dev_err_probe(dev, PTR_ERR(priv->usb_extcon), 592 "Failed to get extcon device"); 593 594 priv->adc = devm_iio_channel_get(dev, "headset-detect"); 595 if (IS_ERR(priv->adc)) 596 return dev_err_probe(dev, PTR_ERR(priv->adc), 597 "Failed to get ADC channel"); 598 599 ret = iio_get_channel_type(priv->adc, &channel_type); 600 if (ret) 601 return dev_err_probe(dev, ret, 602 "Failed to get ADC channel type"); 603 if (channel_type != IIO_VOLTAGE) 604 return -EINVAL; 605 606 priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key", 607 GPIOD_IN); 608 if (IS_ERR(priv->gpio_headset_key)) { 609 dev_err(dev, "Failed to get headset key gpio"); 610 return PTR_ERR(priv->gpio_headset_key); 611 } 612 613 priv->gpio_headset_detect = devm_gpiod_get(dev, 614 "headset-detect", GPIOD_IN); 615 if (IS_ERR(priv->gpio_headset_detect)) { 616 dev_err(dev, "Failed to get headset detect gpio"); 617 return PTR_ERR(priv->gpio_headset_detect); 618 } 619 620 /* Update card-name if provided through DT, else use default name */ 621 snd_soc_of_parse_card_name(card, "model"); 622 623 ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); 624 if (ret < 0) { 625 /* Backwards compatible way */ 626 ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); 627 if (ret < 0) { 628 dev_err(dev, "Audio routing invalid/unspecified\n"); 629 return ret; 630 } 631 } 632 633 aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt; 634 635 cpu = of_get_child_by_name(dev->of_node, "cpu"); 636 if (!cpu) 637 return -EINVAL; 638 639 codec = of_get_child_by_name(dev->of_node, "codec"); 640 if (!codec) { 641 ret = -EINVAL; 642 goto out; 643 } 644 645 for_each_card_prelinks(card, i, dai_link) { 646 dai_link->codecs->of_node = of_parse_phandle(codec, 647 "sound-dai", 0); 648 if (!dai_link->codecs->of_node) { 649 ret = -EINVAL; 650 goto out; 651 } 652 } 653 654 /* Set CPU and platform of_node for main DAI */ 655 aries_dai[0].cpus->of_node = of_parse_phandle(cpu, 656 "sound-dai", 0); 657 if (!aries_dai[0].cpus->of_node) { 658 ret = -EINVAL; 659 goto out; 660 } 661 662 aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node; 663 664 /* Set CPU of_node for BT DAI */ 665 aries_dai[2].cpus->of_node = of_parse_phandle(cpu, 666 "sound-dai", 1); 667 if (!aries_dai[2].cpus->of_node) { 668 ret = -EINVAL; 669 goto out; 670 } 671 672 ret = devm_snd_soc_register_component(dev, &aries_component, 673 aries_ext_dai, ARRAY_SIZE(aries_ext_dai)); 674 if (ret < 0) { 675 dev_err(dev, "Failed to register component: %d\n", ret); 676 goto out; 677 } 678 679 ret = devm_snd_soc_register_card(dev, card); 680 if (ret) 681 dev_err(dev, "snd_soc_register_card() failed:%d\n", ret); 682 683 out: 684 of_node_put(cpu); 685 of_node_put(codec); 686 687 return ret; 688 } 689 690 static struct platform_driver aries_audio_driver = { 691 .driver = { 692 .name = "aries-audio-wm8994", 693 .of_match_table = of_match_ptr(samsung_wm8994_of_match), 694 .pm = &snd_soc_pm_ops, 695 }, 696 .probe = aries_audio_probe, 697 }; 698 699 module_platform_driver(aries_audio_driver); 700 701 MODULE_DESCRIPTION("ALSA SoC ARIES WM8994"); 702 MODULE_LICENSE("GPL"); 703 MODULE_ALIAS("platform:aries-audio-wm8994"); 704