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