brintos

brintos / linux-shallow public Read only

0
0
Text · 17.6 KiB · 01716df Raw
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