703 lines · c
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 2400000018 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 else52 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 so172 * we only have access to the left side SPK configs,173 * but SPKOUTR isn't bridged so when playing back in174 * stereo, we only get the left hand channel. The only175 * option we're left with is to force the AIF into mono176 * 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 else272 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 operations310 */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 else360 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_CBM_CFM,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_CBS_CFS514 | 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_CBM_CFM520 | 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