[alsa-devel] [PATCH 1/2] Add initial support of Mitac mioa701 device SoC.

Robert Jarzmik robert.jarzmik at free.fr
Thu Jan 8 19:42:25 CET 2009


This machine driver enables sound functions on Mitac mio
a701 smartphone. Build upon ASoC v1, it handles :
 - rear speaker
 - front speaker
 - microphone
 - GSM

A global "Mio Mode" switch is provided to cope with audio
path setup. It ensures balance on audio chip line, which if
not respected can produce a lot of heat and even fry the
battery behind the wm9713 and the speaker amplificator.

It doesn't cope with :
 - headset jack (will be integrade after jack support has
   hit ASoC v2)
 - master volume control (depending on current Mio Mode,
   will be submitted in a second patch)

This driver is backported from ASoc v2.

Signed-off-by: Robert Jarzmik <robert.jarzmik at free.fr>
---
 sound/soc/pxa/Kconfig          |    9 +
 sound/soc/pxa/Makefile         |    2 +
 sound/soc/pxa/mioa701_wm9713.c |  571 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 582 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/pxa/mioa701_wm9713.c

diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index f82e106..b385404 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -97,3 +97,12 @@ config SND_SOC_ZYLONITE
 	help
 	  Say Y if you want to add support for SoC audio on the
 	  Marvell Zylonite reference platform.
+
+config SND_PXA2XX_SOC_MIOA701
+        tristate "SoC Audio support for MIO A701"
+        depends on SND_PXA2XX_SOC && MACH_MIOA701
+        select SND_PXA2XX_SOC_AC97
+        select SND_SOC_WM9713
+        help
+          Say Y if you want to add support for SoC audio on the
+          MIO A701.
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index 08a9f27..9a6d27c 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -18,6 +18,7 @@ snd-soc-spitz-objs := spitz.o
 snd-soc-em-x270-objs := em-x270.o
 snd-soc-palm27x-objs := palm27x.o
 snd-soc-zylonite-objs := zylonite.o
+snd-soc-mioa701-objs := mioa701_wm9713.o
 
 obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
 obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
@@ -26,4 +27,5 @@ obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
 obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
 obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
 obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
 obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
new file mode 100644
index 0000000..dbf6799
--- /dev/null
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -0,0 +1,571 @@
+/*
+ * Handles the Mitac mioa701 SoC system
+ *
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-ac97.h"
+#include "../codecs/wm9713.h"
+
+#define ARRAY_AND_SIZE(x)	(x), ARRAY_SIZE(x)
+
+#define AC97_GPIO_PULL		0x58
+
+/* define the scenarios */
+#define MIO_AUDIO_OFF			0
+#define MIO_GSM_AUDIO_HANDSET		1
+#define MIO_GSM_AUDIO_HEADSET		2
+#define MIO_GSM_AUDIO_HANDSFREE		3
+#define MIO_GSM_AUDIO_BLUETOOTH		4
+#define MIO_STEREO_TO_SPEAKER		5
+#define MIO_STEREO_TO_HEADPHONES	6
+#define MIO_CAPTURE_HANDSET		7
+#define MIO_CAPTURE_HEADSET		8
+#define MIO_CAPTURE_BLUETOOTH		9
+
+static int mio_scenario = MIO_AUDIO_OFF;
+
+static int phone_stream_start(struct snd_soc_codec *codec);
+static int phone_stream_stop(struct snd_soc_codec *codec);
+
+struct mio_mixes_t {
+	char *mixname;
+	int  val;
+};
+
+static const struct mio_mixes_t mixes_reset_all[] = {
+	/* left HP mixer */
+	{"Left HP Mixer PC Beep Playback Switch", 0},
+	{"Left HP Mixer Voice Playback Switch",	  0},
+	{"Left HP Mixer Aux Playback Switch",	  0},
+	{"Left HP Mixer Bypass Playback Switch",  0},
+	{"Left HP Mixer PCM Playback Switch",	  0},
+	{"Left HP Mixer MonoIn Playback Switch",  0},
+	{"Left HP Mixer Capture Headphone Mux",	  0},
+
+	/* right HP mixer */
+	{"Right HP Mixer PC Beep Playback Switch", 0},
+	{"Right HP Mixer Voice Playback Switch",   0},
+	{"Right HP Mixer Aux Playback Switch",	   0},
+	{"Right HP Mixer Bypass Playback Switch",  0},
+	{"Right HP Mixer PCM Playback Switch",	   0},
+	{"Right HP Mixer MonoIn Playback Switch",  0},
+	{"Right HP Mixer Capture Headphone Mux",   0},
+
+	/* speaker mixer */
+	{"Speaker Mixer PC Beep Playback Switch", 0},
+	{"Speaker Mixer Voice Playback Switch",	  0},
+	{"Speaker Mixer Aux Playback Switch",	  0},
+	{"Speaker Mixer Bypass Playback Switch",  0},
+	{"Speaker Mixer PCM Playback Switch",	  0},
+	{"Speaker Mixer MonoIn Playback Switch",  0},
+	{"Speaker Mixer Mic 1 Sidetone Switch",	  0},
+
+	/* mono mixer */
+	{"Mono Mixer PC Beep Playback Switch", 0},
+	{"Mono Mixer Voice Playback Switch",   0},
+	{"Mono Mixer Aux Playback Switch",     0},
+	{"Mono Mixer Bypass Playback Switch",  0},
+	{"Mono Mixer PCM Playback Switch",     0},
+	{"Mono Mixer Capture Mono Mux",	       0},
+	{"Mono Mixer MonoIn Playback Switch",  0},
+	{"Mono Mixer Mic 1 Sidetone Switch",   0},
+	{"Mono Playback Switch",	       0},
+
+	/* headphone muxers */
+	{"Left Headphone Out Mux", 0},
+	{"Right Headphone Out Mux", 0},
+
+	/* speaker muxer */
+	{"Left Speaker Out Mux", 0},
+	{"Right Speaker Out Mux", 0},
+
+	/* Out3 muxer */
+	{ "Out 3 Mux", 0},
+
+	{ NULL, 0 }
+};
+
+static const struct mio_mixes_t mixes_gsm_call_headset[] = {
+	/*
+	 * GSM Out to Headset HPL Path
+	 *   => PCBeep -> Headphone Mixer, Headphone Mixer -> HPL
+	 */
+	{ "Left HP Mixer PC Beep Playback Switch", 1 },
+	{ "Left Headphone Out Mux", 2 },
+	/*
+	 * GSM Out to Headset HPR Path
+	 *   => MonoIn -> Headphone Mixer, Headphone Mixer -> HPR
+	 */
+	{ "Right HP Mixer MonoIn Playback Switch" , 1 },
+	{ "Right Headphone Out Mux", 2 },
+	/*
+	 * LineL to GSM In
+	 * LineL -> MonoMixer, MonoMixer -> Mono, Unmute Mono Mixer
+	 */
+	{ "Mono Mixer Bypass Playback Switch",	1},
+	{ "Mono Out Mux", 2 },
+	{ "Mono Playback Switch", 1},
+	{ NULL, 0 }
+};
+
+static const struct mio_mixes_t mixes_gsm_call_handset[] = {
+	/*
+	 * GSM Out to Front Speaker HPL Path
+	 *   => PCBeep -> Headphone Mixer, Headphone Mixer -> HPL
+	 */
+	{ "Left HP Mixer PC Beep Playback Switch", 1 },
+	{ "Left Headphone Out Mux", 2 },
+	/*
+	 * GSM Out to Front Speaker Out3 Path
+	 *   => MonoIn -> Speaker Mixer, Speaker Mixer -> Inv1, Inv1 -> Out3
+	 */
+	{ "Speaker Mixer MonoIn Playback Switch" , 1 },
+	{ "DAC Inv Mux 1", 2 },
+	{ "Out 3 Mux", 2 },
+	/*
+	 * MIC1 to GSM In
+	 *   => MIC1 -> MICA, MICA -> Mono Mixer, Mono Mixer -> MONO,
+	 *      UnMute Mono Mixer
+	 */
+	{ "Mic A Source", 0 },
+	{ "Mono Mixer Mic 1 Sidetone Switch", 1 },
+	{ "Mono Out Mux", 2 },
+	{ "Mono Playback Switch", 1},
+	{ NULL, 0 }
+};
+
+static const struct mio_mixes_t mixes_gsm_call_handsfree[] = {
+	/*
+	 * GSM Out to Rear Speaker SPKL Path
+	 *   => PCBeep -> Speaker Mixer, Speaker Mixer -> Inv1, Inv1 -> SPKL
+	 */
+	{ "Speaker Mixer PC Beep Playback Switch", 1 },
+	{ "DAC Inv Mux 1", 2 },
+	{ "Left Speaker Out Mux", 4 },
+	/*
+	 * GSM Out to Rear Speaker SPKR Path
+	 *   => MonoIn -> Speaker Mixer, Speaker Mixer -> SPKR
+	 */
+	{ "Speaker Mixer MonoIn Playback Switch" , 1 },
+	{ "Right Speaker Out Mux", 3 },
+	/*
+	 * MIC1 to GSM In
+	 *   => MIC1 -> MICA, MICA -> Mono Mixer, Mono Mixer -> MONO,
+	 *      Unmute Mono Mixer
+	 */
+	{ "Mic A Source", 0 },
+	{ "Mono Mixer Mic 1 Sidetone Switch", 1 },
+	{ "Mono Out Mux", 2 },
+	{ "Mono Playback Switch", 1},
+	{ NULL, 0 }
+};
+
+static const struct mio_mixes_t mixes_stereo_to_rearspeaker[] = {
+	/*
+	 * PCM to Rear Speakers
+	 *   => PCM -> Speaker Mixer, Speaker Mixer -> Inv1, Inv1 -> SPKL,
+	 *      Speaker Mixer -> SPKR
+	 */
+	{ "Speaker Mixer PCM Playback Switch", 1},
+	{ "DAC Inv Mux 1", 2 },
+	{ "Left Speaker Out Mux", 4 },
+	{ "Right Speaker Out Mux", 3 },
+	{ NULL, 0 }
+};
+
+struct snd_kcontrol *mioa701_kctrl_byname(struct snd_soc_codec *codec, char *n)
+{
+	struct snd_ctl_elem_id rid;
+
+	memset(&rid, 0, sizeof(rid));
+	rid.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+	strncpy(rid.name, n, sizeof(rid.name));
+	return snd_ctl_find_id(codec->card, &rid);
+}
+
+void setup_muxers(struct snd_soc_codec *codec, const struct mio_mixes_t mixes[])
+{
+	int pos = 0;
+	struct snd_kcontrol *kctl;
+	struct snd_ctl_elem_value ucontrol;
+	char mname[44];
+
+	while (mixes[pos].mixname) {
+		memset(mname, 0, 44);
+		strncpy(mname, mixes[pos].mixname, 43);
+		kctl = mioa701_kctrl_byname(codec, mname);
+		memset(&ucontrol, 0, sizeof(ucontrol));
+		if (kctl) {
+			kctl->get(kctl, &ucontrol);
+			ucontrol.value.enumerated.item[0] = mixes[pos].val;
+			kctl->put(kctl, &ucontrol);
+		}
+		pos++;
+	}
+}
+
+#define NB_ENDP ARRAY_SIZE(endpn)
+static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario)
+{
+	static char *endpn[] = { "Front Speaker", "Rear Speaker",
+				 "GSM Line Out", "GSM Line In",
+				 "Headset Mic", "Front Mic", "Headset" };
+	static const int typ_endps[][NB_ENDP] = {
+		{ 0, 0, 0, 0, 0, 0, 0 }, /* MIO_AUDIO_OFF		*/
+		{ 1, 0, 1, 1, 0, 1, 0 }, /* MIO_GSM_AUDIO_HANDSET	*/
+		{ 0, 0, 1, 1, 1, 0, 1 }, /* MIO_GSM_AUDIO_HEADSET	*/
+		{ 0, 1, 1, 1, 0, 1, 0 }, /* MIO_GSM_AUDIO_HANDSFREE*/
+		{ 0, 0, 1, 1, 0, 0, 0 }, /* MIO_GSM_AUDIO_BLUETOOTH*/
+		{ 0, 1, 0, 0, 0, 0, 0 }, /* MIO_STEREO_TO_SPEAKER	*/
+		{ 0, 0, 0, 0, 0, 0, 1 }, /* MIO_STEREO_TO_HEADPHONES	*/
+		{ 0, 0, 0, 0, 0, 1, 0 }, /* MIO_CAPTURE_HANDSET		*/
+		{ 0, 0, 0, 0, 1, 0, 0 }, /* MIO_CAPTURE_HEADSET		*/
+		{ 0, 0, 0, 0, 0, 0, 0 }, /* MIO_CAPTURE_BLUETOOTH	*/
+	};
+	const int *endps = typ_endps[scenario];
+	int i;
+
+	for (i = 0; i < NB_ENDP; i++)
+		if (endps[i])
+			snd_soc_dapm_enable_pin(codec, endpn[i]);
+		else
+			snd_soc_dapm_disable_pin(codec, endpn[i]);
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+static int get_scenario(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = mio_scenario;
+	return 0;
+}
+
+static int isPhoneMode(int scenario)
+{
+	int onPhone = 0;
+
+	switch (scenario) {
+	case MIO_GSM_AUDIO_HANDSET:
+	case MIO_GSM_AUDIO_HEADSET:
+	case MIO_GSM_AUDIO_BLUETOOTH:
+	case MIO_GSM_AUDIO_HANDSFREE:
+		onPhone = 1;
+	}
+
+	return onPhone;
+}
+
+static void switch_mio_mode(struct snd_soc_codec *codec, int new_scenario)
+{
+	int wasPhone = 0, willPhone = 0;
+
+	wasPhone  = isPhoneMode(mio_scenario);
+	willPhone = isPhoneMode(new_scenario);
+
+	mio_scenario = new_scenario;
+	set_scenario_endpoints(codec, mio_scenario);
+
+	if (!wasPhone && willPhone)
+		phone_stream_start(codec);
+	if (wasPhone && !willPhone)
+		phone_stream_stop(codec);
+
+	setup_muxers(codec, mixes_reset_all);
+	switch (mio_scenario) {
+	case MIO_STEREO_TO_SPEAKER:
+		setup_muxers(codec, mixes_stereo_to_rearspeaker);
+		break;
+	case MIO_GSM_AUDIO_HANDSET:
+		setup_muxers(codec, mixes_gsm_call_handset);
+		break;
+	case MIO_GSM_AUDIO_HANDSFREE:
+		setup_muxers(codec, mixes_gsm_call_handsfree);
+		break;
+	case MIO_GSM_AUDIO_HEADSET:
+		setup_muxers(codec, mixes_gsm_call_headset);
+		break;
+	default:
+		break;
+	}
+}
+
+static int set_scenario(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+
+	if (mio_scenario == ucontrol->value.integer.value[0])
+		return 0;
+
+	switch_mio_mode(codec, ucontrol->value.integer.value[0]);
+	return 1;
+}
+
+static int phone_stream_start(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_stream_event(codec, "AC97 HiFi",
+				  SND_SOC_DAPM_STREAM_START);
+	return 0;
+}
+
+static int phone_stream_stop(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_stream_event(codec, "AC97 HiFi",
+				  SND_SOC_DAPM_STREAM_STOP);
+	return 0;
+}
+
+/* Use GPIO8 for rear speaker amplificator */
+static int rear_amp_power(struct snd_soc_codec *codec, int power)
+{
+	unsigned short reg;
+
+	if (power) {
+		reg = snd_soc_read(codec, AC97_GPIO_CFG);
+		snd_soc_write(codec, AC97_GPIO_CFG, reg | 0x0100);
+		reg = snd_soc_read(codec, AC97_GPIO_PULL);
+		snd_soc_write(codec, AC97_GPIO_PULL, reg | (1<<15));
+	} else {
+		reg = snd_soc_read(codec, AC97_GPIO_CFG);
+		snd_soc_write(codec, AC97_GPIO_CFG, reg & ~0x0100);
+		reg = snd_soc_read(codec, AC97_GPIO_PULL);
+		snd_soc_write(codec, AC97_GPIO_PULL, reg & ~(1<<15));
+	}
+
+	return 0;
+}
+
+static int rear_amp_event(struct snd_soc_dapm_widget *widget,
+			  struct snd_kcontrol *kctl, int event)
+{
+	struct snd_soc_codec *codec = widget->codec;
+	int rc;
+
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		rc = rear_amp_power(codec, 1);
+	else
+		rc = rear_amp_power(codec, 0);
+
+	return rc;
+}
+
+static const char *mio_scenarios[] = {
+	"Off",
+	"GSM Handset",
+	"GSM Headset",
+	"GSM Handsfree",
+	"GSM Bluetooth",
+	"PCM Speaker",
+	"Headphones",
+	"Capture Handset",
+	"Capture Headset",
+	"Capture Bluetooth"
+};
+static const struct soc_enum mio_scenario_enum[] = {
+	SOC_ENUM_SINGLE_EXT(10, mio_scenarios),
+};
+
+static const struct snd_kcontrol_new mioa701_ctrls[] = {
+	SOC_ENUM_EXT("Mio Mode", mio_scenario_enum[0],
+		     get_scenario, set_scenario),
+};
+
+/* mioa701 machine dapm widgets */
+static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Front Speaker", NULL),
+	SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event),
+	SND_SOC_DAPM_MIC("Headset", NULL),
+	SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+	SND_SOC_DAPM_LINE("GSM Line In", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Front Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Call Mic */
+	{"Mic Bias", NULL, "Front Mic"},
+	{"MIC1", NULL, "Mic Bias"},
+
+	/* Headset Mic */
+	{"LINEL", NULL, "Headset Mic"},
+	{"LINER", NULL, "Headset Mic"},
+
+	/* GSM Module */
+	{"MONOIN", NULL, "GSM Line Out"},
+	{"PCBEEP", NULL, "GSM Line Out"},
+	{"GSM Line In", NULL, "MONO"},
+
+	/* headphone connected to HPL, HPR */
+	{"Headset", NULL, "HPL"},
+	{"Headset", NULL, "HPR"},
+
+	/* front speaker connected to HPL, OUT3 */
+	{"Front Speaker", NULL, "HPL"},
+	{"Front Speaker", NULL, "OUT3"},
+
+	/* rear speaker connected to SPKL, SPKR */
+	{"Rear Speaker", NULL, "SPKL"},
+	{"Rear Speaker", NULL, "SPKR"},
+};
+
+static int mioa701_wm9713_init(struct snd_soc_codec *codec)
+{
+	int i, ret;
+	unsigned short reg;
+
+	/* Add test specific controls */
+	for (i = 0; i < ARRAY_SIZE(mioa701_ctrls); i++) {
+		ret = snd_ctl_add(codec->card,
+				  snd_soc_cnew(&mioa701_ctrls[i], codec, NULL));
+		if (ret < 0)
+			return ret;
+	}
+
+	/* Add mioa701 specific widgets */
+	snd_soc_dapm_new_controls(codec, ARRAY_AND_SIZE(mioa701_dapm_widgets));
+
+	/* Set up mioa701 specific audio path audio_mapnects */
+	snd_soc_dapm_add_routes(codec, ARRAY_AND_SIZE(audio_map));
+
+	/* initialize mioa701 codec pins */
+	set_scenario_endpoints(codec, mio_scenario);
+
+	/* Prepare GPIO8 for rear speaker amplificator */
+	reg = codec->read(codec, AC97_GPIO_CFG);
+	codec->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+
+	/* Prepare MIC input */
+	reg = codec->read(codec, AC97_3D_CONTROL);
+	codec->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+
+	snd_soc_dapm_sync(codec);
+
+	return 0;
+}
+
+#define mioa701_wm9713_suspend NULL
+#define mioa701_wm9713_resume  NULL
+
+static struct snd_soc_ops mioa701_ops;
+
+static struct snd_soc_dai_link mioa701_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_HIFI],
+		.codec_dai = &wm9713_dai[WM9713_DAI_AC97_HIFI],
+		.init = mioa701_wm9713_init,
+		.ops = &mioa701_ops,
+	},
+	{
+		.name = "AC97 Aux",
+		.stream_name = "AC97 Aux",
+		.cpu_dai = &pxa_ac97_dai[PXA2XX_DAI_AC97_AUX],
+		.codec_dai = &wm9713_dai[WM9713_DAI_AC97_AUX],
+		.ops = &mioa701_ops,
+	},
+};
+
+static struct snd_soc_card mioa701 = {
+	.name = "MioA701",
+	.platform = &pxa2xx_soc_platform,
+	.dai_link = mioa701_dai,
+	.num_links = ARRAY_SIZE(mioa701_dai),
+};
+
+static struct snd_soc_device mioa701_snd_devdata = {
+	.card = &mioa701,
+	.codec_dev = &soc_codec_dev_wm9713,
+};
+
+static struct platform_device *mioa701_snd_device;
+
+static int mioa701_wm9713_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!machine_is_mioa701())
+		return -ENODEV;
+
+	mioa701_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!mioa701_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(mioa701_snd_device, &mioa701_snd_devdata);
+	mioa701_snd_devdata.dev = &mioa701_snd_device->dev;
+
+	ret = platform_device_add(mioa701_snd_device);
+	if (!ret)
+		return 0;
+
+	platform_device_put(mioa701_snd_device);
+	return ret;
+}
+
+static int __devexit mioa701_wm9713_remove(struct platform_device *pdev)
+{
+	platform_device_unregister(mioa701_snd_device);
+	return 0;
+}
+
+static struct platform_driver mioa701_wm9713_driver = {
+	.probe		= mioa701_wm9713_probe,
+	.remove		= __devexit_p(mioa701_wm9713_remove),
+	.suspend	= mioa701_wm9713_suspend,
+	.resume		= mioa701_wm9713_resume,
+	.driver		= {
+		.name		= "mioa701-wm9713",
+		.owner		= THIS_MODULE,
+	},
+};
+
+static int __init mioa701_asoc_init(void)
+{
+	return platform_driver_register(&mioa701_wm9713_driver);
+}
+
+static void __exit mioa701_asoc_exit(void)
+{
+	platform_driver_unregister(&mioa701_wm9713_driver);
+}
+
+module_init(mioa701_asoc_init);
+module_exit(mioa701_asoc_exit);
+
+/* Module information */
+MODULE_AUTHOR("Robert Jarzmik (rjarzmik at free.fr)");
+MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701");
+MODULE_LICENSE("GPL");
-- 
1.5.6.5



More information about the Alsa-devel mailing list