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