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 .params = &baseband_params, 487 .ignore_suspend = 1, 488 SND_SOC_DAILINK_REG(baseband), 489 }, 490 { 491 .name = "WM8994 AIF3", 492 .stream_name = "Bluetooth", 493 .params = &bluetooth_params, 494 .ignore_suspend = 1, 495 SND_SOC_DAILINK_REG(bluetooth), 496 }, 497 }; 498 499 static struct snd_soc_card aries_card = { 500 .name = "ARIES", 501 .owner = THIS_MODULE, 502 .dai_link = aries_dai, 503 .num_links = ARRAY_SIZE(aries_dai), 504 .controls = aries_controls, 505 .num_controls = ARRAY_SIZE(aries_controls), 506 .dapm_widgets = aries_dapm_widgets, 507 .num_dapm_widgets = ARRAY_SIZE(aries_dapm_widgets), 508 .late_probe = aries_late_probe, 509 }; 510 511 static const struct aries_wm8994_variant fascinate4g_variant = { 512 .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS 513 | SND_SOC_DAIFMT_IB_NF, 514 .has_fm_radio = false, 515 }; 516 517 static const struct aries_wm8994_variant aries_variant = { 518 .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM 519 | SND_SOC_DAIFMT_IB_NF, 520 .has_fm_radio = true, 521 }; 522 523 static const struct of_device_id samsung_wm8994_of_match[] = { 524 { 525 .compatible = "samsung,fascinate4g-wm8994", 526 .data = &fascinate4g_variant, 527 }, 528 { 529 .compatible = "samsung,aries-wm8994", 530 .data = &aries_variant, 531 }, 532 { /* sentinel */ }, 533 }; 534 MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match); 535 536 static int aries_audio_probe(struct platform_device *pdev) 537 { 538 struct device_node *np = pdev->dev.of_node; 539 struct device_node *cpu, *codec, *extcon_np; 540 struct device *dev = &pdev->dev; 541 struct snd_soc_card *card = &aries_card; 542 struct aries_wm8994_data *priv; 543 struct snd_soc_dai_link *dai_link; 544 const struct of_device_id *match; 545 enum iio_chan_type channel_type; 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 ret = iio_get_channel_type(priv->adc, &channel_type); 598 if (ret) 599 return dev_err_probe(dev, ret, 600 "Failed to get ADC channel type"); 601 if (channel_type != IIO_VOLTAGE) 602 return -EINVAL; 603 604 priv->gpio_headset_key = devm_gpiod_get(dev, "headset-key", 605 GPIOD_IN); 606 if (IS_ERR(priv->gpio_headset_key)) { 607 dev_err(dev, "Failed to get headset key gpio"); 608 return PTR_ERR(priv->gpio_headset_key); 609 } 610 611 priv->gpio_headset_detect = devm_gpiod_get(dev, 612 "headset-detect", GPIOD_IN); 613 if (IS_ERR(priv->gpio_headset_detect)) { 614 dev_err(dev, "Failed to get headset detect gpio"); 615 return PTR_ERR(priv->gpio_headset_detect); 616 } 617 618 /* Update card-name if provided through DT, else use default name */ 619 snd_soc_of_parse_card_name(card, "model"); 620 621 ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); 622 if (ret < 0) { 623 dev_err(dev, "Audio routing invalid/unspecified\n"); 624 return ret; 625 } 626 627 aries_dai[1].dai_fmt = priv->variant->modem_dai_fmt; 628 629 cpu = of_get_child_by_name(dev->of_node, "cpu"); 630 if (!cpu) 631 return -EINVAL; 632 633 codec = of_get_child_by_name(dev->of_node, "codec"); 634 if (!codec) { 635 ret = -EINVAL; 636 goto out; 637 } 638 639 for_each_card_prelinks(card, i, dai_link) { 640 dai_link->codecs->of_node = of_parse_phandle(codec, 641 "sound-dai", 0); 642 if (!dai_link->codecs->of_node) { 643 ret = -EINVAL; 644 goto out; 645 } 646 } 647 648 /* Set CPU and platform of_node for main DAI */ 649 aries_dai[0].cpus->of_node = of_parse_phandle(cpu, 650 "sound-dai", 0); 651 if (!aries_dai[0].cpus->of_node) { 652 ret = -EINVAL; 653 goto out; 654 } 655 656 aries_dai[0].platforms->of_node = aries_dai[0].cpus->of_node; 657 658 /* Set CPU of_node for BT DAI */ 659 aries_dai[2].cpus->of_node = of_parse_phandle(cpu, 660 "sound-dai", 1); 661 if (!aries_dai[2].cpus->of_node) { 662 ret = -EINVAL; 663 goto out; 664 } 665 666 ret = devm_snd_soc_register_component(dev, &aries_component, 667 aries_ext_dai, ARRAY_SIZE(aries_ext_dai)); 668 if (ret < 0) { 669 dev_err(dev, "Failed to register component: %d\n", ret); 670 goto out; 671 } 672 673 ret = devm_snd_soc_register_card(dev, card); 674 if (ret) 675 dev_err(dev, "snd_soc_register_card() failed:%d\n", ret); 676 677 out: 678 of_node_put(cpu); 679 of_node_put(codec); 680 681 return ret; 682 } 683 684 static struct platform_driver aries_audio_driver = { 685 .driver = { 686 .name = "aries-audio-wm8994", 687 .of_match_table = of_match_ptr(samsung_wm8994_of_match), 688 .pm = &snd_soc_pm_ops, 689 }, 690 .probe = aries_audio_probe, 691 }; 692 693 module_platform_driver(aries_audio_driver); 694 695 MODULE_DESCRIPTION("ALSA SoC ARIES WM8994"); 696 MODULE_LICENSE("GPL"); 697 MODULE_ALIAS("platform:aries-audio-wm8994"); 698