[alsa-devel] [PATCH 17/19] ALSA: ymu831: add codec driver

Yoichi Yuasa yuasa at linux-mips.org
Wed Jan 16 09:43:28 CET 2013


Signed-off-by: Yoichi Yuasa <yuasa at linux-mips.org>
---
 sound/soc/codecs/ymu831/Makefile      |    2 +-
 sound/soc/codecs/ymu831/ymu831.c      | 5235 +++++++++++++++++++++++++++++++++
 sound/soc/codecs/ymu831/ymu831.h      |   48 +
 sound/soc/codecs/ymu831/ymu831_priv.h |  278 ++
 4 files changed, 5562 insertions(+), 1 deletion(-)
 create mode 100644 sound/soc/codecs/ymu831/ymu831.c
 create mode 100644 sound/soc/codecs/ymu831/ymu831.h
 create mode 100644 sound/soc/codecs/ymu831/ymu831_priv.h

diff --git a/sound/soc/codecs/ymu831/Makefile b/sound/soc/codecs/ymu831/Makefile
index 3fd53fe..ada24db 100644
--- a/sound/soc/codecs/ymu831/Makefile
+++ b/sound/soc/codecs/ymu831/Makefile
@@ -1,4 +1,4 @@
-snd-soc-ymu831-objs := \
+snd-soc-ymu831-objs := ymu831.o \
 	mcbdspdrv.o	\
 	mccdspdrv.o	\
 	mcdevif.o	\
diff --git a/sound/soc/codecs/ymu831/ymu831.c b/sound/soc/codecs/ymu831/ymu831.c
new file mode 100644
index 0000000..62c4a90
--- /dev/null
+++ b/sound/soc/codecs/ymu831/ymu831.c
@@ -0,0 +1,5235 @@
+/*
+ * YMU831 ASoC codec driver
+ *
+ * Copyright (c) 2012 Yamaha Corporation
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.	In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *	claim that you wrote the original software. If you use this software
+ *	in a product, an acknowledgment in the product documentation would be
+ *	appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *	misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*
+ * changelog:
+ * - change in the Linux coding style
+ * - remove unnecessary comments
+ * - remove unused codes
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include <linux/spi/spi.h>
+
+#include <sound/hwdep.h>
+#include <sound/initval.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include "mcdevif.h"
+#include "mcdriver.h"
+#include "ymu831.h"
+#include "ymu831_cfg.h"
+#include "ymu831_ctl.h"
+#include "ymu831_path_cfg.h"
+#include "ymu831_priv.h"
+#include "ymu831_vol.h"
+
+#define MC_ASOC_DRIVER_VERSION	"1.0.1"
+
+#define MC_ASOC_RATE		SNDRV_PCM_RATE_8000_192000
+#define MC_ASOC_FORMATS		(SNDRV_PCM_FMTBIT_S16_LE |	\
+				 SNDRV_PCM_FMTBIT_S20_3LE |	\
+				 SNDRV_PCM_FMTBIT_S24_3LE)
+
+#define get_port_id(id)		(id - 1)
+
+#define PORT_MUSIC		0
+#define PORT_EXT		1
+#define PORT_VOICE		2
+#define PORT_HIFI		3
+
+#define DIO_MUSIC		0
+#define DIO_VOICE		1
+#define LOUT1			3
+#define LOUT2			4
+#define LIN1			3
+#define LIN1_LOUT1		3
+#define LIN1_LOUT2		5
+
+#define DSP_PRM_OUTPUT		0
+#define DSP_PRM_INPUT		1
+#define DSP_PRM_VC_1MIC		2
+#define DSP_PRM_VC_2MIC		3
+#define DSP_PRM_BASE		0
+#define DSP_PRM_USER		1
+
+struct mc_asoc_info_store {
+	u32 get;
+	u32 set;
+	size_t offset;
+	u32 flags;
+};
+
+static const struct mc_asoc_info_store info_store_tbl[] = {
+	{
+	 .get = MCDRV_GET_CLOCKSW,
+	 .set = MCDRV_SET_CLOCKSW,
+	 .offset = offsetof(struct mc_asoc_data, clocksw_store),
+	 },
+	{
+	 .get = MCDRV_GET_DIGITALIO,
+	 .set = MCDRV_SET_DIGITALIO,
+	 .offset = offsetof(struct mc_asoc_data, dio_store),
+	 .flags = 0xfff,
+	 },
+	{
+	 .get = MCDRV_GET_DIGITALIO_PATH,
+	 .set = MCDRV_SET_DIGITALIO_PATH,
+	 .offset = offsetof(struct mc_asoc_data, diopath_store),
+	 .flags = 0x7ff,
+	 },
+	{
+	 .get = MCDRV_GET_PATH,
+	 .set = MCDRV_SET_PATH,
+	 .offset = offsetof(struct mc_asoc_data, path_store),
+	 },
+	{
+	 .get = MCDRV_GET_VOLUME,
+	 .set = MCDRV_SET_VOLUME,
+	 .offset = offsetof(struct mc_asoc_data, vol_store),
+	 },
+	{
+	 .get = MCDRV_GET_SWAP,
+	 .set = MCDRV_SET_SWAP,
+	 .offset = offsetof(struct mc_asoc_data, swap_store),
+	 .flags = 0x7fff},
+};
+
+struct snd_soc_codec *mc_asoc_codec;
+
+static u8 mc_asoc_ver_id = 1;
+static bool mc_asoc_suspended;
+static u8 mc_asoc_hpimpclass = 0xff;
+static u8 mc_asoc_jack_status;
+
+static struct mcdrv_vol_info mc_asoc_vol_info_mute;
+
+static u8 mc_asoc_main_mic = MAIN_MIC;
+static u8 mc_asoc_sub_mic = SUB_MIC;
+static u8 mc_asoc_hs_mic = HEADSET_MIC;
+static u8 mc_asoc_mic1_bias = MIC1_BIAS;
+static u8 mc_asoc_mic2_bias = MIC2_BIAS;
+static u8 mc_asoc_mic3_bias = MIC3_BIAS;
+static u8 mc_asoc_mic4_bias = MIC4_BIAS;
+
+static u8 mc_asoc_audio_play_port = DIO_MUSIC;
+static u8 mc_asoc_audio_cap_port = DIO_MUSIC;
+static u8 mc_asoc_voice_port = DIO_VOICE;
+static u8 mc_asoc_rate = MCDRV_FS_48000;
+
+static int set_bias_level(struct snd_soc_codec *codec,
+			  enum snd_soc_bias_level level)
+{
+	codec->dapm.bias_level = level;
+
+	return 0;
+}
+
+static int read_cache(struct snd_soc_codec *codec, unsigned int reg)
+{
+	int ret;
+	unsigned int val;
+
+	ret = snd_soc_cache_read(codec, reg, &val);
+	if (ret) {
+		dev_err(codec->dev, "Cache read to %x failed: %d\n", reg, ret);
+		return ret;
+	}
+
+	return val;
+}
+
+static int get_mic_block_on(u8 mic)
+{
+	switch (mic) {
+	case MIC_1:
+		return MCDRV_ASRC_MIC1_ON;
+	case MIC_2:
+		return MCDRV_ASRC_MIC2_ON;
+	case MIC_3:
+		return MCDRV_ASRC_MIC3_ON;
+	case MIC_4:
+		return MCDRV_ASRC_MIC4_ON;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+static int get_main_mic_block_on(void)
+{
+	return get_mic_block_on(mc_asoc_main_mic);
+}
+
+static int get_sub_mic_block_on(void)
+{
+	return get_mic_block_on(mc_asoc_sub_mic);
+}
+
+static int get_hs_mic_block_on(void)
+{
+	return get_mic_block_on(mc_asoc_hs_mic);
+}
+
+static int get_unused_mic_block_on(void)
+{
+	int ret = MCDRV_ASRC_MIC1_ON | MCDRV_ASRC_MIC2_ON |
+	    MCDRV_ASRC_MIC3_ON | MCDRV_ASRC_MIC4_ON;
+	if ((mc_asoc_main_mic == MIC_1)
+	    || (mc_asoc_sub_mic == MIC_1)
+	    || (mc_asoc_hs_mic == MIC_1))
+		ret &= ~MCDRV_ASRC_MIC1_ON;
+
+	if ((mc_asoc_main_mic == MIC_2)
+	    || (mc_asoc_sub_mic == MIC_2)
+	    || (mc_asoc_hs_mic == MIC_2))
+		ret &= ~MCDRV_ASRC_MIC2_ON;
+
+	if ((mc_asoc_main_mic == MIC_3)
+	    || (mc_asoc_sub_mic == MIC_3)
+	    || (mc_asoc_hs_mic == MIC_3))
+		ret &= ~MCDRV_ASRC_MIC3_ON;
+
+	if ((mc_asoc_main_mic == MIC_4)
+	    || (mc_asoc_sub_mic == MIC_4)
+	    || (mc_asoc_hs_mic == MIC_4))
+		ret &= ~MCDRV_ASRC_MIC4_ON;
+
+	return ret;
+}
+
+static int get_incall_mic(struct snd_soc_codec *codec, int output_path)
+{
+	switch (output_path) {
+	case MC_ASOC_OUTPUT_PATH_SP:
+		return read_cache(codec, MC_ASOC_INCALL_MIC_SP);
+	case MC_ASOC_OUTPUT_PATH_RC:
+	case MC_ASOC_OUTPUT_PATH_SP_RC:
+	case MC_ASOC_OUTPUT_PATH_LO1_RC:
+	case MC_ASOC_OUTPUT_PATH_LO2_RC:
+		return read_cache(codec, MC_ASOC_INCALL_MIC_RC);
+	case MC_ASOC_OUTPUT_PATH_HP:
+	case MC_ASOC_OUTPUT_PATH_SP_HP:
+	case MC_ASOC_OUTPUT_PATH_LO1_HP:
+	case MC_ASOC_OUTPUT_PATH_LO2_HP:
+		return read_cache(codec, MC_ASOC_INCALL_MIC_HP);
+	case MC_ASOC_OUTPUT_PATH_LO1:
+	case MC_ASOC_OUTPUT_PATH_SP_LO1:
+	case MC_ASOC_OUTPUT_PATH_LO2_LO1:
+		return read_cache(codec, MC_ASOC_INCALL_MIC_LO1);
+	case MC_ASOC_OUTPUT_PATH_LO2:
+	case MC_ASOC_OUTPUT_PATH_SP_LO2:
+	case MC_ASOC_OUTPUT_PATH_LO1_LO2:
+		return read_cache(codec, MC_ASOC_INCALL_MIC_LO2);
+	case MC_ASOC_OUTPUT_PATH_HS:
+	case MC_ASOC_OUTPUT_PATH_BT:
+	case MC_ASOC_OUTPUT_PATH_SP_BT:
+	case MC_ASOC_OUTPUT_PATH_LO1_BT:
+	case MC_ASOC_OUTPUT_PATH_LO2_BT:
+		return MC_ASOC_INCALL_MIC_MAINMIC;
+	default:
+		break;
+	}
+
+	return -EIO;
+}
+
+struct mixer_path_ctl_info {
+	int audio_mode_play;
+	int audio_mode_cap;
+	int output_path;
+	int input_path;
+	int incall_mic;
+	int mainmic_play;
+	int submic_play;
+	int msmic_play;
+	int hsmic_play;
+	int btmic_play;
+	int lin1_play;
+	int dtmf_control;
+	int dtmf_output;
+};
+
+static int get_mixer_path_ctl_info(struct snd_soc_codec *codec,
+				   struct mixer_path_ctl_info *info)
+{
+	info->audio_mode_play = read_cache(codec, MC_ASOC_AUDIO_MODE_PLAY);
+	if (info->audio_mode_play < 0)
+		return -EIO;
+
+	info->audio_mode_cap = read_cache(codec, MC_ASOC_AUDIO_MODE_CAP);
+	if (info->audio_mode_cap < 0)
+		return -EIO;
+
+	info->output_path = read_cache(codec, MC_ASOC_OUTPUT_PATH);
+	if (info->output_path < 0)
+		return -EIO;
+
+	info->input_path = read_cache(codec, MC_ASOC_INPUT_PATH);
+	if (info->input_path < 0)
+		return -EIO;
+
+	info->incall_mic = get_incall_mic(codec, info->output_path);
+	if (info->incall_mic < 0)
+		return -EIO;
+
+	info->dtmf_control = read_cache(codec, MC_ASOC_DTMF_CONTROL);
+	if (info->dtmf_control < 0)
+		return -EIO;
+
+	info->dtmf_output = read_cache(codec, MC_ASOC_DTMF_OUTPUT);
+	if (info->dtmf_output < 0)
+		return -EIO;
+
+	info->mainmic_play = read_cache(codec, MC_ASOC_MAINMIC_PLAYBACK_PATH);
+	if (info->mainmic_play < 0)
+		return -EIO;
+
+	info->submic_play = read_cache(codec, MC_ASOC_SUBMIC_PLAYBACK_PATH);
+	if (info->submic_play < 0)
+		return -EIO;
+
+	info->msmic_play = read_cache(codec, MC_ASOC_2MIC_PLAYBACK_PATH);
+	if (info->msmic_play < 0)
+		return -EIO;
+
+	info->hsmic_play = read_cache(codec, MC_ASOC_HSMIC_PLAYBACK_PATH);
+	if (info->hsmic_play < 0)
+		return -EIO;
+
+	info->btmic_play = read_cache(codec, MC_ASOC_BTMIC_PLAYBACK_PATH);
+	if (info->btmic_play < 0)
+		return -EIO;
+
+	info->lin1_play = read_cache(codec, MC_ASOC_LIN1_PLAYBACK_PATH);
+	if (info->lin1_play < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int get_path_preset_idx(struct mixer_path_ctl_info *info)
+{
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM
+	    && info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCOMM) {
+		switch (info->output_path) {
+		case MC_ASOC_OUTPUT_PATH_BT:
+			return 25;
+		case MC_ASOC_OUTPUT_PATH_SP_BT:
+		case MC_ASOC_OUTPUT_PATH_LO1_BT:
+		case MC_ASOC_OUTPUT_PATH_LO2_BT:
+			return 26;
+		default:
+			return 24;
+		}
+	}
+
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM2
+	    && info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCOMM) {
+		if (info->output_path == MC_ASOC_OUTPUT_PATH_BT)
+			return 63;
+		else if (info->output_path == MC_ASOC_OUTPUT_PATH_SP_BT
+			 || info->output_path == MC_ASOC_OUTPUT_PATH_LO1_BT
+			 || info->output_path == MC_ASOC_OUTPUT_PATH_LO2_BT)
+			return 64;
+		else
+			return 62;
+	}
+
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL) {
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 13;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 14;
+			default:
+				return 12;
+			}
+		}
+
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 19;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 20;
+			default:
+				return 18;
+			}
+		}
+	}
+
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL2) {
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 51;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 52;
+			default:
+				return 50;
+			}
+		}
+
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 57;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 58;
+			default:
+				return 56;
+			}
+		}
+	}
+
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL) {
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 16;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 17;
+			default:
+				return 15;
+			}
+		}
+
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 22;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 23;
+			default:
+				return 21;
+			}
+		}
+	}
+
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL2) {
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 54;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 55;
+			default:
+				return 53;
+			}
+		}
+
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL) {
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 60;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 61;
+			default:
+				return 59;
+			}
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO &&
+	     (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_OFF ||
+	      info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCALL ||
+	      info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCOMM))
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL &&
+		(info->audio_mode_cap == MC_ASOC_AUDIO_MODE_OFF ||
+		 info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCOMM))
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL2 &&
+		(info->audio_mode_cap == MC_ASOC_AUDIO_MODE_OFF ||
+		 info->audio_mode_cap == MC_ASOC_AUDIO_MODE_INCOMM))) {
+		switch (info->output_path) {
+		case MC_ASOC_OUTPUT_PATH_BT:
+			if (mc_asoc_rate == MCDRV_FS_96000
+			    || mc_asoc_rate == MCDRV_FS_192000)
+				return -1;
+			return 2;
+		case MC_ASOC_OUTPUT_PATH_SP_BT:
+		case MC_ASOC_OUTPUT_PATH_LO1_BT:
+		case MC_ASOC_OUTPUT_PATH_LO2_BT:
+			if (mc_asoc_rate == MCDRV_FS_96000
+			    || mc_asoc_rate == MCDRV_FS_192000)
+				return -1;
+			return 3;
+		default:
+			if (mc_asoc_rate == MCDRV_FS_96000
+			    || mc_asoc_rate == MCDRV_FS_192000)
+				return 27;
+			return 1;
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_OFF &&
+	     (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO ||
+	      info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL))
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL &&
+		info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO)
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL2 &&
+		info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO)
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM &&
+		(info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO ||
+		 info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL))
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM2 &&
+		(info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO ||
+		 info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL))) {
+		switch (info->input_path) {
+		case MC_ASOC_INPUT_PATH_BT:
+			if (mc_asoc_rate == MCDRV_FS_96000
+			    || mc_asoc_rate == MCDRV_FS_192000)
+				return -1;
+			return 5;
+		case MC_ASOC_INPUT_PATH_VOICECALL:
+		case MC_ASOC_INPUT_PATH_VOICEUPLINK:
+		case MC_ASOC_INPUT_PATH_VOICEDOWNLINK:
+			if ((mc_asoc_rate == MCDRV_FS_96000)
+			    || (mc_asoc_rate == MCDRV_FS_192000))
+				return 28;
+			return 4;
+		default:
+			if (mc_asoc_rate == MCDRV_FS_96000
+			    || mc_asoc_rate == MCDRV_FS_192000)
+				return 28;
+			return 4;
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO &&
+	     (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO ||
+	      info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL))
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL &&
+		info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO)
+	    || (info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL2 &&
+		info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO)) {
+		switch (info->input_path) {
+		case MC_ASOC_INPUT_PATH_VOICECALL:
+		case MC_ASOC_INPUT_PATH_VOICEUPLINK:
+		case MC_ASOC_INPUT_PATH_VOICEDOWNLINK:
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				if (mc_asoc_rate == MCDRV_FS_96000
+				    || mc_asoc_rate == MCDRV_FS_192000)
+					return -1;
+				return 8;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				if (mc_asoc_rate == MCDRV_FS_96000
+				    || mc_asoc_rate == MCDRV_FS_192000)
+					return -1;
+				return 10;
+			default:
+				if (mc_asoc_rate == MCDRV_FS_96000
+				    || mc_asoc_rate == MCDRV_FS_192000)
+					return 29;
+				return 6;
+			}
+		default:
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				if (mc_asoc_rate == MCDRV_FS_96000
+				    || mc_asoc_rate == MCDRV_FS_192000)
+					return -1;
+				if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+					return 9;
+				return 8;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				if (mc_asoc_rate == MCDRV_FS_96000
+				    || mc_asoc_rate == MCDRV_FS_192000)
+					return -1;
+				if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+					return 11;
+				return 10;
+			default:
+				if (info->input_path == MC_ASOC_INPUT_PATH_BT) {
+					if (mc_asoc_rate == MCDRV_FS_96000
+					    || mc_asoc_rate == MCDRV_FS_192000)
+						return -1;
+					return 7;
+				}
+
+				if (mc_asoc_rate == MCDRV_FS_96000
+				    || mc_asoc_rate == MCDRV_FS_192000)
+					return 29;
+				return 6;
+			}
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_OFF ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL2 ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM2)
+	    && info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIOEX) {
+		switch (info->input_path) {
+		case MC_ASOC_INPUT_PATH_VOICECALL:
+		case MC_ASOC_INPUT_PATH_VOICEUPLINK:
+		case MC_ASOC_INPUT_PATH_VOICEDOWNLINK:
+			return 30;
+		default:
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 31;
+			return 30;
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL2)
+	    && info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIOEX) {
+		switch (info->input_path) {
+		case MC_ASOC_INPUT_PATH_VOICECALL:
+		case MC_ASOC_INPUT_PATH_VOICEUPLINK:
+		case MC_ASOC_INPUT_PATH_VOICEDOWNLINK:
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				return 34;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				return 36;
+			default:
+				return 32;
+			}
+		default:
+			switch (info->output_path) {
+			case MC_ASOC_OUTPUT_PATH_BT:
+				if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+					return 35;
+				return 34;
+			case MC_ASOC_OUTPUT_PATH_SP_BT:
+			case MC_ASOC_OUTPUT_PATH_LO1_BT:
+			case MC_ASOC_OUTPUT_PATH_LO2_BT:
+				if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+					return 37;
+				return 36;
+			default:
+				if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+					return 33;
+				return 32;
+			}
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_OFF ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCALL ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_INCOMM)
+	    && info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIOVR) {
+		switch (info->input_path) {
+		case MC_ASOC_INPUT_PATH_VOICECALL:
+		case MC_ASOC_INPUT_PATH_VOICEUPLINK:
+		case MC_ASOC_INPUT_PATH_VOICEDOWNLINK:
+			return 38;
+		default:
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 39;
+			return 38;
+		}
+	}
+
+	if ((info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO ||
+	     info->audio_mode_play == MC_ASOC_AUDIO_MODE_AUDIO_INCALL)
+	    && info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIOVR) {
+		switch (info->output_path) {
+		case MC_ASOC_OUTPUT_PATH_BT:
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 43;
+			return 42;
+		case MC_ASOC_OUTPUT_PATH_SP_BT:
+		case MC_ASOC_OUTPUT_PATH_LO1_BT:
+		case MC_ASOC_OUTPUT_PATH_LO2_BT:
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 45;
+			return 44;
+		default:
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 41;
+			return 40;
+		}
+	}
+
+	if (info->audio_mode_play == MC_ASOC_AUDIO_MODE_KARAOKE) {
+		if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_OFF) {
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 47;
+			return 46;
+		} else if (info->audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO) {
+			if (info->input_path == MC_ASOC_INPUT_PATH_BT)
+				return 49;
+			return 48;
+		}
+	}
+
+	return 0;
+}
+
+static inline int is_incall(int preset_idx)
+{
+	if ((preset_idx >= 12 && preset_idx <= 23)
+	    || (preset_idx >= 50 && preset_idx <= 61))
+		return 1;
+
+	return 0;
+}
+
+static inline int is_incommunication(int preset_idx)
+{
+	if ((preset_idx >= 24 && preset_idx <= 26)
+	    || (preset_idx >= 62 && preset_idx <= 64))
+		return 1;
+
+	return 0;
+}
+
+static void set_vol_mute_flag(size_t offset, u8 lr, u8 mute)
+{
+	s16 *vp = (void *)&mc_asoc_vol_info_mute + offset;
+
+	if (offset == (size_t) -1)
+		return;
+
+	if (mute == 1)
+		*(vp + lr) = 0xa000;
+	else
+		*(vp + lr) = 0;
+}
+
+static u8 get_vol_mute_flag(size_t offset, u8 lr)
+{
+	s16 *vp;
+
+	if (offset == (size_t) -1)
+		return 1;	/* mute */
+
+	vp = (void *)&mc_asoc_vol_info_mute + offset;
+
+	return (*(vp + lr) != 0);
+}
+
+static int get_master_vol(struct snd_soc_codec *codec, s16 *db, int reg, int i)
+{
+	unsigned int v;
+	int cache, sum, sw, vol;
+
+	cache = read_cache(codec, MC_ASOC_DVOL_MASTER);
+	if (cache < 0)
+		return -EIO;
+
+	v = (cache >> (i * 8)) & 0xff;
+	sw = v & 0x80;
+	vol = sw ? (v & 0x7f) : 0;
+	if (!vol)
+		*db = vreg_map[reg].volmap[0];
+	else {
+		sum = *db + vreg_map[MC_ASOC_DVOL_MASTER].volmap[vol];
+		if (sum < vreg_map[reg].volmap[0])
+			sum = vreg_map[reg].volmap[0];
+		*db = sum;
+	}
+
+	return 0;
+}
+
+static int get_voice_vol(struct snd_soc_codec *codec, s16 *db, int reg, int i)
+{
+	unsigned int v;
+	int cache, sum, sw, vol;
+
+	cache = read_cache(codec, MC_ASOC_DVOL_VOICE);
+	if (cache < 0)
+		return -EIO;
+
+	v = (cache >> (i * 8)) & 0xff;
+	sw = v & 0x80;
+	vol = sw ? (v & 0x7f) : 0;
+	if (!vol)
+		*db = vreg_map[reg].volmap[0];
+	else {
+		sum = *db + vreg_map[MC_ASOC_DVOL_VOICE].volmap[vol];
+		if (sum < vreg_map[reg].volmap[0])
+			sum = vreg_map[reg].volmap[0];
+		*db = sum;
+	}
+
+	return 0;
+}
+
+static int get_aplay_vol(struct snd_soc_codec *codec, s16 *db, int reg, int i,
+			 int aplay_reg, struct mixer_path_ctl_info *info,
+			 int preset_idx)
+{
+	unsigned int v;
+	int cache, input_path, sw, vol;
+	s16 aplay_db;
+
+	if (preset_idx >= 46 && preset_idx <= 49)
+		return 0;
+
+	if (is_incall(preset_idx) || is_incommunication(preset_idx))
+		return 0;
+
+	if (!(preset_idx < 12 || preset_idx == 28 || preset_idx > 29))
+		return 0;
+
+	cache = read_cache(codec, aplay_reg);
+	if (cache < 0)
+		return -EIO;
+
+	v = (cache >> (i * 8)) & 0xff;
+	sw = v & 0x80;
+	vol = sw ? (v & 0x7f) : 0;
+	aplay_db = vreg_map[reg].volmap[vol];
+	input_path = info->input_path;
+
+	if (reg == MC_ASOC_DVOL_ADIF1IN) {
+		if (info->lin1_play == 1) {
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_LIN1) {
+				*db = aplay_db;
+				return 0;
+			}
+		}
+
+		if (info->mainmic_play == 1) {
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_MAINMIC) {
+				*db = aplay_db;
+				return 0;
+			}
+		}
+
+		if (info->submic_play == 1) {
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_SUBMIC) {
+				*db = aplay_db;
+				return 0;
+			}
+		}
+
+		if (info->msmic_play == 1) {
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+				*db = aplay_db;
+				return 0;
+			}
+		}
+
+		if (info->hsmic_play == 1) {
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_HS) {
+				*db = aplay_db;
+				return 0;
+			}
+		}
+
+		return 0;
+	}
+
+	if (reg == MC_ASOC_AVOL_LINEIN1) {
+		if (info->lin1_play == 1) {
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_LIN1)
+				*db = aplay_db;
+		}
+
+		return 0;
+	}
+
+	if (reg == MC_ASOC_AVOL_MIC1) {
+		if (mc_asoc_main_mic == MIC_1) {
+			if (info->mainmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_MAINMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_sub_mic == MIC_1) {
+			if (info->submic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_SUBMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_hs_mic == MIC_1 && info->hsmic_play == 1)
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_HS)
+				*db = aplay_db;
+
+		return 0;
+	}
+
+	if (reg == MC_ASOC_AVOL_MIC2) {
+		if (mc_asoc_main_mic == MIC_2) {
+			if (info->mainmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_MAINMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_sub_mic == MIC_2) {
+			if (info->submic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_SUBMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_hs_mic == MIC_2 && info->hsmic_play == 1)
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_HS)
+				*db = aplay_db;
+
+		return 0;
+	}
+
+	if (reg == MC_ASOC_AVOL_MIC3) {
+		if (mc_asoc_main_mic == MIC_3) {
+			if (info->mainmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_MAINMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_sub_mic == MIC_3) {
+			if (info->submic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_SUBMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_hs_mic == MIC_3 && info->hsmic_play == 1)
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_HS)
+				*db = aplay_db;
+
+		return 0;
+	}
+
+	if (reg == MC_ASOC_AVOL_MIC4) {
+		if (mc_asoc_main_mic == MIC_4) {
+			if (info->mainmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_MAINMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_sub_mic == MIC_4) {
+			if (info->submic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path ==
+				    MC_ASOC_INPUT_PATH_SUBMIC) {
+					*db = aplay_db;
+					return 0;
+				}
+
+			if (info->msmic_play == 1)
+				if (preset_idx < 4 || preset_idx >= 38
+				    || input_path == MC_ASOC_INPUT_PATH_BT
+				    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+					*db = aplay_db;
+					return 0;
+				}
+		}
+
+		if (mc_asoc_hs_mic == MIC_4 && info->hsmic_play == 1)
+			if (preset_idx < 4 || preset_idx >= 38
+			    || input_path == MC_ASOC_INPUT_PATH_BT
+			    || input_path == MC_ASOC_INPUT_PATH_HS)
+				*db = aplay_db;
+	}
+
+	return 0;
+}
+
+static int set_vol_info(struct snd_soc_codec *codec,
+			struct mcdrv_vol_info *vol_info, int reg,
+			struct mixer_path_ctl_info *mixer_info, int preset_idx)
+{
+	s16 *vp;
+	int i, cache;
+
+	if (!codec)
+		return -EIO;
+
+	if (reg >= MC_ASOC_AVOL_SP_GAIN)
+		return -EIO;
+
+	if (vreg_map[reg].offset != (size_t) -1) {
+		vp = (void *)vol_info + vreg_map[reg].offset;
+		cache = read_cache(codec, reg);
+		if (cache < 0)
+			return -EIO;
+
+		for (i = 0; i < vreg_map[reg].channels; i++, vp++) {
+			unsigned int v;
+			int sw, vol, size;
+			bool sw_overwrite;
+			s16 db, db_max, map;
+
+			v = (cache >> (i * 8)) & 0xff;
+			sw = v & 0x80;
+			sw_overwrite = false;
+
+			if (is_incall(preset_idx)) {
+				switch (reg) {
+				case MC_ASOC_DVOL_VOICEOUT:
+					if (mc_asoc_voice_port == DIO_VOICE
+					    && sw)
+						sw_overwrite = true;
+					break;
+				case MC_ASOC_DVOL_DAC0OUT:
+					if (mc_asoc_voice_port == LIN1_LOUT1
+					    && sw)
+						sw_overwrite = true;
+					break;
+				case MC_ASOC_DVOL_DAC1OUT:
+					if (mc_asoc_voice_port == LIN1_LOUT2
+					    && sw)
+						sw_overwrite = true;
+					break;
+				default:
+					break;
+				}
+			} else if (is_incommunication(preset_idx)) {
+				if (reg == MC_ASOC_DVOL_VOICEOUT) {
+					if (mc_asoc_voice_port == DIO_VOICE
+					    && sw)
+						sw_overwrite = true;
+				}
+			}
+
+			if (sw_overwrite)
+				sw = read_cache(codec, MC_ASOC_VOICE_RECORDING);
+
+			vol = sw ? (v & 0x7f) : 0;
+
+			if (get_vol_mute_flag(vreg_map[reg].offset, i))
+				db = vreg_map[reg].volmap[0];
+			else
+				db = vreg_map[reg].volmap[vol];
+
+			if (reg == MC_ASOC_DVOL_MUSICIN) {
+				if (mc_asoc_audio_play_port != DIO_MUSIC
+				    || !vol)
+					db = vreg_map[reg].volmap[0];
+				else if (get_master_vol(codec, &db, reg, i))
+					return -EIO;
+			} else if (reg == MC_ASOC_DVOL_VOICEIN) {
+				if (is_incall(preset_idx))
+					db = vreg_map[reg].volmap[vol];
+				else if (mc_asoc_voice_port == LIN1_LOUT1
+					 || mc_asoc_voice_port == LIN1_LOUT2
+					 || !vol)
+					db = vreg_map[reg].volmap[0];
+				else if (get_voice_vol(codec, &db, reg, i))
+					return -EIO;
+			} else if (reg == MC_ASOC_DVOL_ADIF1IN) {
+				if (get_aplay_vol(codec, &db, reg, i,
+						  MC_ASOC_DVOL_APLAY_D,
+						  mixer_info, preset_idx))
+					return -EIO;
+				if (mc_asoc_audio_play_port == LIN1)
+					if (get_master_vol(codec, &db, reg, i))
+						return -EIO;
+			} else if (reg == MC_ASOC_AVOL_LINEIN1) {
+				if (is_incall(preset_idx)) {
+					if ((mc_asoc_voice_port == LIN1_LOUT1 ||
+					     mc_asoc_voice_port == LIN1_LOUT2)
+					    && get_voice_vol(codec, &db, reg,
+							     i))
+						return -EIO;
+				} else {
+					if (get_aplay_vol(codec, &db, reg, i,
+							  MC_ASOC_DVOL_APLAY_A,
+							  mixer_info,
+							  preset_idx))
+						return -EIO;
+				}
+			} else if ((reg == MC_ASOC_AVOL_MIC1 ||
+				    reg == MC_ASOC_AVOL_MIC2 ||
+				    reg == MC_ASOC_AVOL_MIC3 ||
+				    reg == MC_ASOC_AVOL_MIC4)
+				   && get_aplay_vol(codec, &db, reg, i,
+						    MC_ASOC_DVOL_APLAY_A,
+						    mixer_info, preset_idx)) {
+				return -EIO;
+			} else if (reg == MC_ASOC_AVOL_HP
+				   && (mc_asoc_hpimpclass != (u8) -1 &&
+				       db > vreg_map[reg].volmap[0])) {
+				size = ARRAY_SIZE(volmap_hp) - 1;
+				db_max = vreg_map[MC_ASOC_AVOL_HP].volmap[size];
+				db += hp_vol_imp_table[mc_asoc_hpimpclass] << 8;
+				map = vreg_map[MC_ASOC_AVOL_HP].volmap[0];
+				if (db < map)
+					db = map;
+				else if (db > db_max)
+					db = db_max;
+			} else if (reg == MC_ASOC_DVOL_DAC0OUT
+				   && (mc_asoc_hpimpclass != (u8) -1 &&
+				       db > vreg_map[reg].volmap[0])) {
+				size = ARRAY_SIZE(volmap_digital) - 1;
+				db_max = volmap_digital[size];
+				db +=
+				    dac0_vol_imp_table[mc_asoc_hpimpclass] << 8;
+				map = volmap_digital[0];
+				if (db < map)
+					db = map;
+				else if (db > db_max)
+					db = db_max;
+			}
+
+			*vp = db | MCDRV_VOL_UPDATE;
+		}
+	}
+
+	return 0;
+}
+
+static int set_volume(struct snd_soc_codec *codec,
+		      struct mixer_path_ctl_info *mixer, int preset_idx)
+{
+	struct mcdrv_vol_info vol_info;
+	int err, reg;
+
+	if (!codec)
+		return -EIO;
+
+	memset(&vol_info, 0, sizeof(struct mcdrv_vol_info));
+
+	for (reg = MC_ASOC_DVOL_MUSICIN; reg < MC_ASOC_AVOL_SP_GAIN; reg++) {
+		err = set_vol_info(codec, &vol_info, reg, mixer, preset_idx);
+		if (err < 0)
+			return err;
+	}
+
+	err = mc_control(MCDRV_SET_VOLUME, (unsigned long)&vol_info, 0);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in MCDRV_SET_VOLUME: %d\n", err);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static inline void mask_source(u32 *src, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++)
+		src[i] = 0x002aaaaa;
+}
+
+static void mask_analog_out_source(struct mcdrv_path_info *path,
+				   struct mixer_path_ctl_info *mixer,
+				   int preset_idx)
+{
+	int output_path;
+
+	output_path = mixer->output_path;
+
+	if (output_path != MC_ASOC_OUTPUT_PATH_SP
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_RC
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_HP
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_LO1
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_LO2
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_BT)
+		mask_source(path->sp, SP_PATH_CHANNELS);
+
+	if (output_path != MC_ASOC_OUTPUT_PATH_RC
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_RC
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_RC
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_RC)
+		mask_source(path->rc, RC_PATH_CHANNELS);
+
+	if (output_path != MC_ASOC_OUTPUT_PATH_HP
+	    && output_path != MC_ASOC_OUTPUT_PATH_HS
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_HP
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_HP
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_HP)
+		mask_source(path->hp, HP_PATH_CHANNELS);
+
+	if (output_path != MC_ASOC_OUTPUT_PATH_LO1
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_LO1
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_RC
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_HP
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_BT
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_LO2
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_LO1) {
+		if (preset_idx < 12) {
+			if (mc_asoc_audio_cap_port == LOUT1) {
+				if (preset_idx <= 3 || preset_idx == 6
+				    || preset_idx == 7)
+					mask_source(path->lout1,
+						    LOUT1_PATH_CHANNELS);
+			} else
+				mask_source(path->lout1, LOUT1_PATH_CHANNELS);
+		} else if (is_incall(preset_idx)) {
+			/* incall */
+			if (mc_asoc_voice_port == LIN1_LOUT1) {
+				/* nothing to do */
+			} else if (mc_asoc_audio_cap_port == LOUT1) {
+				if (preset_idx != 18 && preset_idx != 21
+				    && preset_idx != 56 && preset_idx != 59)
+					mask_source(path->lout1,
+						    LOUT1_PATH_CHANNELS);
+			} else
+				mask_source(path->lout1, LOUT1_PATH_CHANNELS);
+		} else if (preset_idx == 24 || preset_idx >= 26)
+			mask_source(path->lout1, LOUT1_PATH_CHANNELS);
+
+	}
+
+	if (output_path != MC_ASOC_OUTPUT_PATH_LO2
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_LO2
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_RC
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_HP
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_BT
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_LO2
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_LO1) {
+		if (preset_idx < 12) {
+			if (mc_asoc_audio_cap_port == LOUT2) {
+				if (preset_idx <= 3 || preset_idx == 6
+				    || preset_idx == 7)
+					mask_source(path->lout2,
+						    LOUT2_PATH_CHANNELS);
+			} else
+				mask_source(path->lout2, LOUT2_PATH_CHANNELS);
+		} else if (is_incall(preset_idx)) {
+			if (mc_asoc_voice_port == LIN1_LOUT2) {
+				/* nothing to do */
+			} else if (mc_asoc_audio_cap_port == LOUT2) {
+				if (preset_idx != 18 && preset_idx != 21
+				    && preset_idx != 56 && preset_idx != 59)
+					mask_source(path->lout2,
+						    LOUT2_PATH_CHANNELS);
+			} else
+				mask_source(path->lout2, LOUT2_PATH_CHANNELS);
+		} else if (preset_idx == 24 || preset_idx >= 26) {
+			mask_source(path->lout2, LOUT2_PATH_CHANNELS);
+		}
+	}
+}
+
+static void mask_bluetooth_out_source(struct mcdrv_path_info *path,
+				      int output_path)
+{
+	int i;
+
+	if (output_path != MC_ASOC_OUTPUT_PATH_BT
+	    && output_path != MC_ASOC_OUTPUT_PATH_SP_BT
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO1_BT
+	    && output_path != MC_ASOC_OUTPUT_PATH_LO2_BT)
+		for (i = 0; i < EXTOUT_PATH_CHANNELS; i++)
+			path->ext_out[i] = 0x00aaaaaa;
+}
+
+static void mask_adc0_source(struct mcdrv_path_info *path,
+			     struct mixer_path_ctl_info *mixer, int preset_idx)
+{
+	int input_path, output_path, incall_mic;
+	int main_mic_block_on = get_main_mic_block_on();
+	int sub_mic_block_on = get_sub_mic_block_on();
+	int hs_mic_block_on = get_hs_mic_block_on();
+	int unused_mic_block_on = get_unused_mic_block_on();
+
+	if (!is_incall(preset_idx) && !is_incommunication(preset_idx)) {
+		/* !incall */
+		if (preset_idx == 4 || preset_idx == 6
+		    || preset_idx == 8 || preset_idx == 10
+		    || preset_idx == 28 || preset_idx == 29
+		    || preset_idx == 30 || preset_idx == 32
+		    || preset_idx == 34 || preset_idx == 36
+		    || preset_idx == 46 || preset_idx == 48) {
+			/* in capture */
+			input_path = mixer->input_path;
+			if (input_path != MC_ASOC_INPUT_PATH_MAINMIC
+			    && input_path != MC_ASOC_INPUT_PATH_2MIC
+			    && main_mic_block_on != -1) {
+				path->adc0[0] &= ~main_mic_block_on;
+				path->adc0[1] &= ~main_mic_block_on;
+			}
+
+			if (input_path != MC_ASOC_INPUT_PATH_SUBMIC
+			    && input_path != MC_ASOC_INPUT_PATH_2MIC
+			    && sub_mic_block_on != -1) {
+				path->adc0[0] &= ~sub_mic_block_on;
+				path->adc0[1] &= ~sub_mic_block_on;
+			}
+
+			if (input_path != MC_ASOC_INPUT_PATH_HS
+			    && hs_mic_block_on != -1) {
+				path->adc0[0] &= ~hs_mic_block_on;
+				path->adc0[1] &= ~hs_mic_block_on;
+			}
+
+			if (input_path == MC_ASOC_INPUT_PATH_2MIC) {
+				path->adc0[0] &= ~sub_mic_block_on;
+				path->adc0[1] &= ~main_mic_block_on;
+			}
+
+			if (input_path != MC_ASOC_INPUT_PATH_LIN1) {
+				path->adc0[0] &= ~MCDRV_ASRC_LINEIN1_L_ON;
+				path->adc0[1] &= ~MCDRV_ASRC_LINEIN1_R_ON;
+			}
+		} else {
+			if (mixer->mainmic_play != 1 && mixer->msmic_play != 1
+			    && main_mic_block_on != -1) {
+				path->adc0[0] &= ~main_mic_block_on;
+				path->adc0[1] &= ~main_mic_block_on;
+			}
+
+			if (mixer->submic_play != 1 && mixer->msmic_play != 1
+			    && sub_mic_block_on != -1) {
+				path->adc0[0] &= ~sub_mic_block_on;
+				path->adc0[1] &= ~sub_mic_block_on;
+			}
+
+			if (mixer->hsmic_play != 1 && hs_mic_block_on != -1) {
+				path->adc0[0] &= ~hs_mic_block_on;
+				path->adc0[1] &= ~hs_mic_block_on;
+			}
+
+			if (mixer->lin1_play != 1) {
+				path->adc0[0] &= ~MCDRV_ASRC_LINEIN1_ALL_ON;
+				path->adc0[1] &= ~MCDRV_ASRC_LINEIN1_ALL_ON;
+			}
+		}
+	} else {
+		/* incall or incommunication */
+		output_path = mixer->output_path;
+		if (output_path != MC_ASOC_OUTPUT_PATH_BT
+		    && output_path != MC_ASOC_OUTPUT_PATH_SP_BT
+		    && output_path != MC_ASOC_OUTPUT_PATH_LO1_BT
+		    && output_path != MC_ASOC_OUTPUT_PATH_LO2_BT) {
+			if (output_path != MC_ASOC_OUTPUT_PATH_HS) {
+				if (hs_mic_block_on != -1) {
+					path->adc0[0] &= ~hs_mic_block_on;
+					path->adc0[1] &= ~hs_mic_block_on;
+				}
+
+				incall_mic = mixer->incall_mic;
+				if (incall_mic != MC_ASOC_INCALL_MIC_MAINMIC
+				    && incall_mic != MC_ASOC_INCALL_MIC_2MIC
+				    && main_mic_block_on != -1) {
+					path->adc0[0] &= ~main_mic_block_on;
+					path->adc0[1] &= ~main_mic_block_on;
+				}
+
+				if (incall_mic != MC_ASOC_INCALL_MIC_SUBMIC
+				    && incall_mic != MC_ASOC_INCALL_MIC_2MIC
+				    && sub_mic_block_on != -1) {
+					path->adc0[0] &= ~sub_mic_block_on;
+					path->adc0[1] &= ~sub_mic_block_on;
+				}
+
+				if (incall_mic == MC_ASOC_INCALL_MIC_2MIC) {
+					path->adc0[0] &= ~sub_mic_block_on;
+					path->adc0[1] &= ~main_mic_block_on;
+				}
+			} else {
+				if (main_mic_block_on != -1) {
+					path->adc0[0] &= ~main_mic_block_on;
+					path->adc0[1] &= ~main_mic_block_on;
+				}
+
+				if (sub_mic_block_on != -1) {
+					path->adc0[0] &= ~sub_mic_block_on;
+					path->adc0[1] &= ~sub_mic_block_on;
+				}
+			}
+		}
+	}
+
+	path->adc0[0] &= ~unused_mic_block_on;
+	path->adc0[1] &= ~unused_mic_block_on;
+}
+
+static void mask_adc1_source(struct mcdrv_path_info *path,
+			     struct mixer_path_ctl_info *mixer, int preset_idx)
+{
+	int input_path = mixer->input_path;
+	int main_mic_block_on = get_main_mic_block_on();
+	int sub_mic_block_on = get_sub_mic_block_on();
+	int hs_mic_block_on = get_hs_mic_block_on();
+	int unused_mic_block_on = get_unused_mic_block_on();
+
+	/* !incall */
+	if (preset_idx == 38 || preset_idx == 40
+	    || preset_idx == 42 || preset_idx == 44) {
+		/* in capture */
+		if (input_path != MC_ASOC_INPUT_PATH_MAINMIC
+		    && input_path != MC_ASOC_INPUT_PATH_2MIC
+		    && main_mic_block_on != -1)
+			path->adc1[0] &= ~main_mic_block_on;
+
+		if (input_path != MC_ASOC_INPUT_PATH_SUBMIC
+		    && input_path != MC_ASOC_INPUT_PATH_2MIC
+		    && sub_mic_block_on != -1)
+			path->adc1[0] &= ~sub_mic_block_on;
+
+		if (input_path != MC_ASOC_INPUT_PATH_HS
+		    && hs_mic_block_on != -1)
+			path->adc1[0] &= ~hs_mic_block_on;
+
+		if (input_path != MC_ASOC_INPUT_PATH_LIN1)
+			path->adc1[0] &= ~MCDRV_ASRC_LINEIN1_M_ON;
+	}
+
+	path->adc1[0] &= ~unused_mic_block_on;
+}
+
+static void mask_dac_reference(struct mcdrv_path_info *path, int output_path)
+{
+	int i;
+
+	switch (output_path) {
+	case MC_ASOC_OUTPUT_PATH_SP:
+	case MC_ASOC_OUTPUT_PATH_LO2:
+	case MC_ASOC_OUTPUT_PATH_SP_LO2:
+	case MC_ASOC_OUTPUT_PATH_SP_BT:
+	case MC_ASOC_OUTPUT_PATH_LO2_BT:
+	case MC_ASOC_OUTPUT_PATH_LO1_LO2:
+		for (i = 0; i < ADIF2_PATH_CHANNELS; i++)
+			path->adif2[i] &= ~MCDRV_D2SRC_DAC0REF_ON;
+		break;
+	case MC_ASOC_OUTPUT_PATH_RC:
+	case MC_ASOC_OUTPUT_PATH_HP:
+	case MC_ASOC_OUTPUT_PATH_HS:
+	case MC_ASOC_OUTPUT_PATH_LO1:
+	case MC_ASOC_OUTPUT_PATH_LO1_RC:
+	case MC_ASOC_OUTPUT_PATH_LO1_HP:
+	case MC_ASOC_OUTPUT_PATH_LO1_BT:
+	case MC_ASOC_OUTPUT_PATH_SP_RC:
+	case MC_ASOC_OUTPUT_PATH_SP_HP:
+	case MC_ASOC_OUTPUT_PATH_SP_LO1:
+	case MC_ASOC_OUTPUT_PATH_LO2_RC:
+	case MC_ASOC_OUTPUT_PATH_LO2_HP:
+	case MC_ASOC_OUTPUT_PATH_LO2_LO1:
+		for (i = 0; i < ADIF2_PATH_CHANNELS; i++)
+			path->adif2[i] &= ~MCDRV_D2SRC_DAC1REF_ON;
+		break;
+	default:
+		break;
+	}
+}
+
+static void add_path_info(struct mcdrv_path_info *dst_path,
+			  const struct mcdrv_path_info *src_path)
+{
+	int i;
+
+	for (i = 0; i < MUSICOUT_PATH_CHANNELS; i++)
+		dst_path->music_out[i] |= src_path->music_out[i];
+
+	for (i = 0; i < EXTOUT_PATH_CHANNELS; i++)
+		dst_path->ext_out[i] |= src_path->ext_out[i];
+
+	for (i = 0; i < HIFIOUT_PATH_CHANNELS; i++)
+		dst_path->hifi_out[i] |= src_path->hifi_out[i];
+
+	for (i = 0; i < VBOXMIXIN_PATH_CHANNELS; i++)
+		dst_path->vbox_mix_in[i] |= src_path->vbox_mix_in[i];
+
+	for (i = 0; i < AE_PATH_CHANNELS; i++) {
+		dst_path->ae0[i] |= src_path->ae0[i];
+		dst_path->ae1[i] |= src_path->ae1[i];
+		dst_path->ae2[i] |= src_path->ae2[i];
+		dst_path->ae3[i] |= src_path->ae3[i];
+	}
+
+	for (i = 0; i < DAC0_PATH_CHANNELS; i++)
+		dst_path->dac0[i] |= src_path->dac0[i];
+
+	for (i = 0; i < DAC1_PATH_CHANNELS; i++)
+		dst_path->dac1[i] |= src_path->dac1[i];
+
+	for (i = 0; i < VOICEOUT_PATH_CHANNELS; i++)
+		dst_path->voice_out[i] |= src_path->voice_out[i];
+
+	for (i = 0; i < VBOXIOIN_PATH_CHANNELS; i++)
+		dst_path->vbox_io_in[i] |= src_path->vbox_io_in[i];
+
+	for (i = 0; i < VBOXHOSTIN_PATH_CHANNELS; i++)
+		dst_path->vbox_host_in[i] |= src_path->vbox_host_in[i];
+
+	for (i = 0; i < HOSTOUT_PATH_CHANNELS; i++)
+		dst_path->host_out[i] |= src_path->host_out[i];
+
+	for (i = 0; i < ADIF0_PATH_CHANNELS; i++)
+		dst_path->adif0[i] |= src_path->adif0[i];
+
+	for (i = 0; i < ADIF1_PATH_CHANNELS; i++)
+		dst_path->adif1[i] |= src_path->adif1[i];
+
+	for (i = 0; i < ADIF2_PATH_CHANNELS; i++)
+		dst_path->adif2[i] |= src_path->adif2[i];
+
+	for (i = 0; i < ADC0_PATH_CHANNELS; i++)
+		dst_path->adc0[i] |= src_path->adc0[i];
+
+	for (i = 0; i < ADC1_PATH_CHANNELS; i++)
+		dst_path->adc1[i] |= src_path->adc1[i];
+
+	for (i = 0; i < HP_PATH_CHANNELS; i++)
+		dst_path->hp[i] |= src_path->hp[i];
+
+	for (i = 0; i < SP_PATH_CHANNELS; i++)
+		dst_path->sp[i] |= src_path->sp[i];
+
+	for (i = 0; i < RC_PATH_CHANNELS; i++)
+		dst_path->rc[i] |= src_path->rc[i];
+
+	for (i = 0; i < LOUT1_PATH_CHANNELS; i++)
+		dst_path->lout1[i] |= src_path->lout1[i];
+
+	for (i = 0; i < LOUT2_PATH_CHANNELS; i++)
+		dst_path->lout2[i] |= src_path->lout2[i];
+
+	for (i = 0; i < BIAS_PATH_CHANNELS; i++)
+		dst_path->bias[i] |= src_path->bias[i];
+}
+
+static void exchange_adc0_to_pdm(struct mcdrv_path_info *path,
+				 u32 pdm_l_on, u32 pdm_r_on)
+{
+	if (pdm_l_on) {
+		path->adif1[0] &= ~MCDRV_D2SRC_ADC0_ON;
+		path->adif1[0] |= MCDRV_D2SRC_ADC0_OFF | pdm_l_on;
+	}
+
+	if (pdm_r_on) {
+		path->adif1[1] &= ~MCDRV_D2SRC_ADC0_ON;
+		path->adif1[1] |= MCDRV_D2SRC_ADC0_OFF | pdm_r_on;
+	}
+}
+
+static void exchange_adc1_to_pdm(struct mcdrv_path_info *path,
+				 u32 pdm_l_on, u32 pdm_r_on)
+{
+	if (pdm_l_on) {
+		path->adif0[0] &= ~MCDRV_D2SRC_ADC1_ON;
+		path->adif0[0] |= MCDRV_D2SRC_ADC1_OFF | pdm_l_on;
+	}
+
+	if (pdm_r_on) {
+		path->adif0[1] &= ~MCDRV_D2SRC_ADC1_ON;
+		path->adif0[1] |= MCDRV_D2SRC_ADC1_OFF | pdm_r_on;
+	}
+}
+
+static void set_ain_play_path(struct mcdrv_path_info *path,
+			      struct mixer_path_ctl_info *mixer,
+			      int preset_idx, int ignore_input_path)
+{
+	int idx = analog_path_mapping[preset_idx];
+	int input_path = mixer->input_path;
+
+	if (idx >= ARRAY_SIZE(analog_input_path))
+		return;
+
+	if (mixer->mainmic_play == 1) {
+		if (ignore_input_path
+		    || input_path == MC_ASOC_INPUT_PATH_MAINMIC) {
+			add_path_info(path, &analog_input_path[idx]);
+			if (mc_asoc_main_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON,
+						     MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_main_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON,
+						     MCDRV_D2SRC_PDM1_R_ON);
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_bluetooth_out_source(path, mixer->output_path);
+			return;
+		}
+	}
+
+	if (mixer->submic_play == 1) {
+		if (ignore_input_path
+		    || input_path == MC_ASOC_INPUT_PATH_SUBMIC) {
+			add_path_info(path, &analog_input_path[idx]);
+			if (mc_asoc_sub_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON,
+						     MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_sub_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON,
+						     MCDRV_D2SRC_PDM1_R_ON);
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_bluetooth_out_source(path, mixer->output_path);
+			return;
+		}
+	}
+
+	if (mixer->hsmic_play == 1) {
+		if (ignore_input_path || input_path == MC_ASOC_INPUT_PATH_HS) {
+			add_path_info(path, &analog_input_path[idx]);
+			if (mc_asoc_hs_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON,
+						     MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_hs_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON,
+						     MCDRV_D2SRC_PDM1_R_ON);
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_bluetooth_out_source(path, mixer->output_path);
+			return;
+		}
+	}
+
+	if (mixer->msmic_play == 1) {
+		if (ignore_input_path
+		    || input_path == MC_ASOC_INPUT_PATH_2MIC) {
+			add_path_info(path, &analog_input_path[idx]);
+			if (mc_asoc_main_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON, 0);
+			else if (mc_asoc_main_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON, 0);
+			if (mc_asoc_sub_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     0, MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_sub_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     0, MCDRV_D2SRC_PDM1_R_ON);
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_bluetooth_out_source(path, mixer->output_path);
+			return;
+		}
+	}
+
+	if (mixer->lin1_play == 1) {
+		if (ignore_input_path
+		    || input_path == MC_ASOC_INPUT_PATH_LIN1) {
+			add_path_info(path, &analog_input_path[idx]);
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_bluetooth_out_source(path, mixer->output_path);
+			return;
+		}
+	}
+}
+
+static inline void set_bias(struct mcdrv_path_info *path)
+{
+	int mic_bias[BIAS_PATH_CHANNELS] = {
+		mc_asoc_mic1_bias,
+		mc_asoc_mic2_bias,
+		mc_asoc_mic3_bias,
+		mc_asoc_mic4_bias
+	};
+	u32 on[BIAS_PATH_CHANNELS] = {
+		MCDRV_ASRC_MIC1_ON,
+		MCDRV_ASRC_MIC2_ON,
+		MCDRV_ASRC_MIC3_ON,
+		MCDRV_ASRC_MIC4_ON
+	};
+	int i, j;
+
+	for (i = 0; i < BIAS_PATH_CHANNELS; i++) {
+		switch (mic_bias[i]) {
+		case BIAS_ON_ALWAYS:
+			path->bias[i] |= on[i];
+			break;
+		case BIAS_OFF:
+			path->bias[i] &= ~on[i];
+			break;
+		case BIAS_SYNC_MIC:
+			path->bias[i] &= ~on[i];
+			for (j = 0; j < ADC0_PATH_CHANNELS; j++) {
+				if (path->adc0[j] & on[i]) {
+					path->bias[i] |= on[i];
+					break;
+				}
+			}
+
+			for (j = 0; j < ADC1_PATH_CHANNELS; j++) {
+				if (path->adc1[j] & on[i]) {
+					path->bias[i] |= on[i];
+					break;
+				}
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (path->hp[0] & MCDRV_ASRC_DAC0_L_ON
+	    || path->hp[1] & MCDRV_ASRC_DAC0_R_ON) {
+		if (mc_asoc_jack_status)
+			path->bias[3] |= MCDRV_ASRC_MIC4_ON;
+	}
+}
+
+static void get_path_info(struct mcdrv_path_info *path,
+			  struct mixer_path_ctl_info *mixer, int preset_idx)
+{
+	const struct mcdrv_path_info *preset_path;
+	size_t offset;
+	bool mute_dit = false, ain_play = false;
+	int input_path, output_path, audio_mode_play, audio_mode_cap, idx;
+
+	if (mixer->mainmic_play == 1 || mixer->submic_play == 1
+	    || mixer->msmic_play == 1 || mixer->hsmic_play == 1
+	    || mixer->lin1_play == 1)
+		ain_play = true;
+
+	preset_path = &mc_preset_path_info[preset_idx];
+	input_path = mixer->input_path;
+	output_path = mixer->output_path;
+	audio_mode_play = mixer->audio_mode_play;
+	audio_mode_cap = mixer->audio_mode_cap;
+
+	if (mixer->dtmf_control == 1) {
+		if (!(mixer->dtmf_output == MC_ASOC_DTMF_OUTPUT_SP
+		      && output_path != MC_ASOC_OUTPUT_PATH_SP)) {
+			idx = dtmf_path_mapping[preset_idx];
+			if (idx >= ARRAY_SIZE(dtmf_path))
+				return;
+
+			add_path_info(path, &dtmf_path[idx]);
+			mask_analog_out_source(path, mixer, preset_idx);
+			mask_bluetooth_out_source(path, output_path);
+		}
+	}
+
+	if (is_incommunication(preset_idx)) {
+		if (output_path == MC_ASOC_OUTPUT_PATH_BT) {
+			add_path_info(path, preset_path);
+			path->vbox_mix_in[1] = 0x00aaaaaa;
+		} else if (output_path == MC_ASOC_OUTPUT_PATH_SP_BT
+			   || output_path == MC_ASOC_OUTPUT_PATH_LO1_BT
+			   || output_path == MC_ASOC_OUTPUT_PATH_LO2_BT) {
+			add_path_info(path, preset_path);
+			mask_analog_out_source(path, mixer, preset_idx);
+			path->vbox_mix_in[1] = 0x00aaaaaa;
+			mask_dac_reference(path, output_path);
+		} else {
+			add_path_info(path, preset_path);
+
+			switch (mixer->incall_mic) {
+			case MC_ASOC_INCALL_MIC_MAINMIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+				break;
+			case MC_ASOC_INCALL_MIC_SUBMIC:
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+				break;
+			default:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							0);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							0);
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							0,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							0,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			}
+
+			mask_dac_reference(path, output_path);
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_analog_out_source(path, mixer, preset_idx);
+		}
+
+		return;
+	}
+
+	if ((preset_idx >= 12 && preset_idx <= 17)
+	    || (preset_idx >= 50 && preset_idx <= 55)) {
+		if (output_path == MC_ASOC_OUTPUT_PATH_BT) {
+			add_path_info(path, preset_path);
+			path->vbox_mix_in[1] = 0x00aaaaaa;
+		} else if (output_path == MC_ASOC_OUTPUT_PATH_SP_BT
+			   || output_path == MC_ASOC_OUTPUT_PATH_LO1_BT
+			   || output_path == MC_ASOC_OUTPUT_PATH_LO2_BT) {
+			add_path_info(path, preset_path);
+			mask_analog_out_source(path, mixer, preset_idx);
+			path->vbox_mix_in[1] = 0x00aaaaaa;
+			mask_dac_reference(path, output_path);
+		} else {
+			add_path_info(path, preset_path);
+			if (mixer->incall_mic == MC_ASOC_INCALL_MIC_MAINMIC) {
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+			} else if (mixer->incall_mic ==
+				   MC_ASOC_INCALL_MIC_SUBMIC) {
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+			} else {
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							0);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							0);
+
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM1_R_ON);
+
+			}
+
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_analog_out_source(path, mixer, preset_idx);
+			mask_dac_reference(path, output_path);
+		}
+
+		return;
+	}
+
+	if ((preset_idx >= 18 && preset_idx <= 23)
+	    || (preset_idx >= 56 && preset_idx <= 61)) {
+		if (output_path == MC_ASOC_OUTPUT_PATH_BT) {
+			add_path_info(path, preset_path);
+			path->vbox_mix_in[1] = 0x00aaaaaa;
+		} else if (output_path == MC_ASOC_OUTPUT_PATH_SP_BT
+			   || output_path == MC_ASOC_OUTPUT_PATH_LO1_BT
+			   || output_path == MC_ASOC_OUTPUT_PATH_LO2_BT) {
+			add_path_info(path, preset_path);
+			mask_analog_out_source(path, mixer, preset_idx);
+			path->vbox_mix_in[1] = 0x00aaaaaa;
+			mask_dac_reference(path, output_path);
+		} else {
+			add_path_info(path, preset_path);
+			if (mixer->incall_mic == MC_ASOC_INCALL_MIC_MAINMIC) {
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+			} else if (mixer->incall_mic ==
+				   MC_ASOC_INCALL_MIC_SUBMIC) {
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+			} else {
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							0);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							0);
+
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM1_R_ON);
+			}
+
+			mask_adc0_source(path, mixer, preset_idx);
+			mask_analog_out_source(path, mixer, preset_idx);
+			mask_dac_reference(path, output_path);
+		}
+
+		return;
+	}
+
+	if (mixer->btmic_play == 1) {
+		idx = bt_path_mapping[preset_idx];
+		if (bt_path_mapping[preset_idx] < ARRAY_SIZE(bt_input_path)) {
+			add_path_info(path, &bt_input_path[idx]);
+			mask_bluetooth_out_source(path, output_path);
+		}
+	}
+
+	if ((preset_idx >= 1 && preset_idx <= 3) || preset_idx == 27) {
+		if (ain_play)
+			set_ain_play_path(path, mixer, preset_idx, 1);
+		add_path_info(path, preset_path);
+	} else if (preset_idx == 4 || preset_idx == 5 || preset_idx == 28
+		   || preset_idx == 30 || preset_idx == 31) {
+		if (input_path != MC_ASOC_INPUT_PATH_VOICECALL
+		    && input_path != MC_ASOC_INPUT_PATH_VOICEUPLINK
+		    && input_path != MC_ASOC_INPUT_PATH_VOICEDOWNLINK) {
+			if (ain_play == 1) {
+				if (input_path == MC_ASOC_INPUT_PATH_BT)
+					set_ain_play_path(path, mixer,
+							  preset_idx, 1);
+				else
+					set_ain_play_path(path, mixer,
+							  preset_idx, 0);
+			}
+
+			add_path_info(path, preset_path);
+			switch (input_path) {
+			case MC_ASOC_INPUT_PATH_MAINMIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_SUBMIC:
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_2MIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							0);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							0);
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_HS:
+				if (mc_asoc_hs_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_hs_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			default:
+				break;
+			}
+
+			mask_adc0_source(path, mixer, preset_idx);
+			if (input_path != MC_ASOC_INPUT_PATH_2MIC)
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+		} else {
+			add_path_info(path, preset_path);
+			mute_dit = true;
+		}
+	} else if ((preset_idx >= 6 && preset_idx <= 11)
+		   || preset_idx == 29
+		   || (preset_idx >= 32 && preset_idx <= 37)) {
+		if (input_path != MC_ASOC_INPUT_PATH_VOICECALL
+		    && input_path != MC_ASOC_INPUT_PATH_VOICEUPLINK
+		    && input_path != MC_ASOC_INPUT_PATH_VOICEDOWNLINK) {
+			if (ain_play == 1) {
+				if (input_path == MC_ASOC_INPUT_PATH_BT)
+					set_ain_play_path(path, mixer,
+							  preset_idx, 1);
+				else
+					set_ain_play_path(path, mixer,
+							  preset_idx, 0);
+			}
+
+			add_path_info(path, preset_path);
+			switch (input_path) {
+			case MC_ASOC_INPUT_PATH_MAINMIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_SUBMIC:
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_2MIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							0);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							0);
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_HS:
+				if (mc_asoc_hs_mic == MIC_PDM0)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_hs_mic == MIC_PDM1)
+					exchange_adc0_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			default:
+				break;
+			}
+
+			mask_adc0_source(path, mixer, preset_idx);
+			if (input_path != MC_ASOC_INPUT_PATH_2MIC)
+				path->vbox_mix_in[1] = 0x00aaaaaa;
+		} else {
+			add_path_info(path, preset_path);
+			mute_dit = true;
+		}
+	} else if (preset_idx >= 38 && preset_idx <= 45) {
+		if (ain_play == 1)
+			set_ain_play_path(path, mixer, preset_idx, 1);
+		if (input_path != MC_ASOC_INPUT_PATH_VOICECALL
+		    && input_path != MC_ASOC_INPUT_PATH_VOICEUPLINK
+		    && input_path != MC_ASOC_INPUT_PATH_VOICEDOWNLINK) {
+			add_path_info(path, preset_path);
+			switch (input_path) {
+			case MC_ASOC_INPUT_PATH_MAINMIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_SUBMIC:
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_2MIC:
+				if (mc_asoc_main_mic == MIC_PDM0)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							0);
+				if (mc_asoc_main_mic == MIC_PDM1)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							0);
+				if (mc_asoc_sub_mic == MIC_PDM0)
+					exchange_adc1_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_sub_mic == MIC_PDM1)
+					exchange_adc1_to_pdm(path, 0,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			case MC_ASOC_INPUT_PATH_HS:
+				if (mc_asoc_hs_mic == MIC_PDM0)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM0_L_ON,
+							MCDRV_D2SRC_PDM0_R_ON);
+				else if (mc_asoc_hs_mic == MIC_PDM1)
+					exchange_adc1_to_pdm(path,
+							MCDRV_D2SRC_PDM1_L_ON,
+							MCDRV_D2SRC_PDM1_R_ON);
+				break;
+			default:
+				break;
+			}
+			mask_adc1_source(path, mixer, preset_idx);
+		} else {
+			add_path_info(path, preset_path);
+			mute_dit = true;
+		}
+	} else if (preset_idx == 46 || preset_idx == 47
+		   || preset_idx == 48 || preset_idx == 49) {
+		add_path_info(path, preset_path);
+		switch (input_path) {
+		case MC_ASOC_INPUT_PATH_MAINMIC:
+			if (mc_asoc_main_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON,
+						     MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_main_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON,
+						     MCDRV_D2SRC_PDM1_R_ON);
+			break;
+		case MC_ASOC_INPUT_PATH_SUBMIC:
+			if (mc_asoc_sub_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON,
+						     MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_sub_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON,
+						     MCDRV_D2SRC_PDM1_R_ON);
+			break;
+		case MC_ASOC_INPUT_PATH_2MIC:
+			if (mc_asoc_main_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON, 0);
+			else if (mc_asoc_main_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON, 0);
+			if (mc_asoc_sub_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     0, MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_sub_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     0, MCDRV_D2SRC_PDM1_R_ON);
+			break;
+		case MC_ASOC_INPUT_PATH_HS:
+			if (mc_asoc_hs_mic == MIC_PDM0)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM0_L_ON,
+						     MCDRV_D2SRC_PDM0_R_ON);
+			else if (mc_asoc_hs_mic == MIC_PDM1)
+				exchange_adc0_to_pdm(path,
+						     MCDRV_D2SRC_PDM1_L_ON,
+						     MCDRV_D2SRC_PDM1_R_ON);
+			break;
+		default:
+			break;
+		}
+
+		mask_adc0_source(path, mixer, preset_idx);
+	} else if (ain_play == 1)
+		set_ain_play_path(path, mixer, preset_idx, 1);
+
+	mask_analog_out_source(path, mixer, preset_idx);
+	if (preset_idx < 4 || CAPTURE_PORT != CAPTURE_PORT_EXT)
+		mask_bluetooth_out_source(path, output_path);
+
+	offset = vreg_map[MC_ASOC_DVOL_EXTOUT].offset;
+	set_vol_mute_flag(offset, 0, 0);
+	set_vol_mute_flag(offset, 1, 0);
+
+	offset = vreg_map[MC_ASOC_DVOL_MUSICOUT].offset;
+	set_vol_mute_flag(offset, 0, 0);
+	set_vol_mute_flag(offset, 1, 0);
+	if (CAPTURE_PORT == CAPTURE_PORT_EXT) {
+		if (preset_idx >= 4) {
+			path->ext_out[0] = path->music_out[0];
+			path->music_out[0] = 0x00aaaaaa;
+			path->ext_out[1] = path->music_out[1];
+			path->music_out[1] = 0x00aaaaaa;
+			if (mute_dit) {
+				offset = vreg_map[MC_ASOC_DVOL_EXTOUT].offset;
+				set_vol_mute_flag(offset, 0, 1);
+				set_vol_mute_flag(offset, 1, 1);
+			}
+		}
+	} else if (mute_dit) {
+		offset = vreg_map[MC_ASOC_DVOL_MUSICOUT].offset;
+		set_vol_mute_flag(offset, 0, 1);
+		set_vol_mute_flag(offset, 1, 1);
+	}
+}
+
+static void set_adif_source(u8 src, u32 *onoff)
+{
+	switch (src) {
+	case 1:
+		/* ADC0L */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_ADC0_L_ON;
+		break;
+	case 2:
+		/* ADC0R */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_ADC0_R_ON;
+		break;
+	case 3:
+		/* ADC1 */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_ADC1_ON;
+		break;
+	case 4:
+		/* PDM0L */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_PDM0_L_ON;
+		break;
+	case 5:
+		/* PDM0R */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_PDM0_R_ON;
+		break;
+	case 6:
+		/* PDM1L */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_PDM1_L_ON;
+		break;
+	case 7:
+		/* PDM1R */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_PDM1_R_ON;
+		break;
+	case 8:
+		/* DAC0REF */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_DAC0REF_ON;
+		break;
+	case 9:
+		/* DAC1REF */
+		*onoff = 0x00aaaaaa | MCDRV_D2SRC_DAC1REF_ON;
+		break;
+	default:
+		break;
+	}
+}
+
+static int connect_path(struct snd_soc_codec *codec)
+{
+	struct mixer_path_ctl_info mixer_info;
+	struct mcdrv_path_info path_info;
+	int preset_idx = 0;
+	int cache;
+	int err;
+
+	if (get_mixer_path_ctl_info(codec, &mixer_info) < 0)
+		return -EIO;
+
+	preset_idx = get_path_preset_idx(&mixer_info);
+	if (preset_idx < 0 || preset_idx > PRESET_PATH_N)
+		return -EIO;
+
+	memcpy(&path_info, &mc_preset_path_info[0],
+	       sizeof(struct mcdrv_path_info));
+	get_path_info(&path_info, &mixer_info, preset_idx);
+	set_bias(&path_info);
+
+	cache = read_cache(codec, MC_ASOC_ADIF0_SOURCE);
+	if (cache < 0)
+		return -EIO;
+	if ((cache & 0xff) && (cache & 0xff00)) {
+		set_adif_source(cache, &path_info.adif0[0]);
+		set_adif_source(cache >> 8, &path_info.adif0[1]);
+	}
+
+	cache = read_cache(codec, MC_ASOC_ADIF1_SOURCE);
+	if (cache < 0)
+		return -EIO;
+	if ((cache & 0xff) && (cache & 0xff00)) {
+		set_adif_source(cache, &path_info.adif1[0]);
+		set_adif_source(cache >> 8, &path_info.adif1[1]);
+	}
+
+	cache = read_cache(codec, MC_ASOC_ADIF2_SOURCE);
+	if (cache < 0)
+		return -EIO;
+	if ((cache & 0xff) && (cache & 0xff00)) {
+		set_adif_source(cache, &path_info.adif2[0]);
+		set_adif_source(cache >> 8, &path_info.adif2[1]);
+	}
+
+	err = set_volume(codec, &mixer_info, preset_idx);
+	if (err < 0)
+		return err;
+
+	err = mc_control(MCDRV_SET_PATH, (unsigned long)&path_info, 0);
+	if (err < 0)
+		return err;
+
+	return err;
+}
+
+/*
+ * DAI (PCM interface)
+ */
+static int is_dio_modified(struct mcdrv_dio_port *dio_port,
+			   int id, int mode, u32 update)
+{
+	struct mcdrv_dio_info dio_info;
+	struct mcdrv_dio_common *comm1, *comm2;
+	struct mcdrv_dio_dir *dir1, *dir2;
+	struct mcdrv_dio_dit *dit1, *dit2;
+	int err;
+
+	err = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio_info, 0);
+	if (err < 0)
+		return err;
+
+	comm1 = &dio_info.port[id].dio_common;
+	comm2 = &dio_port->dio_common;
+
+	if (update & (MCDRV_MUSIC_COM_UPDATE_FLAG | MCDRV_EXT_COM_UPDATE_FLAG |
+		      MCDRV_HIFI_COM_UPDATE_FLAG)) {
+		if (comm1->master_slave != comm2->master_slave
+		    || comm1->auto_fs != comm2->auto_fs
+		    || comm1->fs != comm2->fs
+		    || comm1->bck_fs != comm2->bck_fs
+		    || comm1->interface != comm2->interface
+		    || comm1->bck_invert != comm2->bck_invert
+		    || comm1->src_thru != comm2->src_thru)
+			return 1;
+
+		if (mode == MCDRV_DIO_PCM
+		    && (comm1->pcm_hiz_transition != comm2->pcm_hiz_transition
+			|| comm1->pcm_frame != comm2->pcm_frame
+			|| comm1->pcm_high_period != comm2->pcm_high_period))
+			return 1;
+	}
+
+	dir1 = &dio_info.port[id].dir;
+	dir2 = &dio_port->dir;
+
+	if (update
+	    & (MCDRV_MUSIC_DIR_UPDATE_FLAG | MCDRV_HIFI_DIR_UPDATE_FLAG)) {
+		if (mode == MCDRV_DIO_DA
+		    && (dir1->da_format.bit_sel != dir2->da_format.bit_sel
+			|| dir1->da_format.mode != dir2->da_format.mode))
+			return 1;
+
+		if (mode != MCDRV_DIO_DA
+		    && (dir1->pcm_format.mono != dir2->pcm_format.mono
+			|| dir1->pcm_format.order != dir2->pcm_format.order
+			|| dir1->pcm_format.law != dir2->pcm_format.law
+			|| dir1->pcm_format.bit_sel !=
+			dir2->pcm_format.bit_sel))
+			return 1;
+	}
+
+	dit1 = &dio_info.port[id].dit;
+	dit2 = &dio_port->dit;
+
+	if (update & (MCDRV_MUSIC_DIT_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG |
+		      MCDRV_HIFI_DIT_UPDATE_FLAG)) {
+		if (mode == MCDRV_DIO_DA
+		    && (dit1->da_format.bit_sel != dit2->da_format.bit_sel
+			|| dit1->da_format.mode != dit2->da_format.mode))
+			return 1;
+
+		if (mode != MCDRV_DIO_DA
+		    && (dit1->pcm_format.mono != dit2->pcm_format.mono
+			|| dit1->pcm_format.order != dit2->pcm_format.order
+			|| dit1->pcm_format.law != dit2->pcm_format.law
+			|| dit1->pcm_format.bit_sel !=
+			dit2->pcm_format.bit_sel))
+			return 1;
+	}
+
+	return 0;
+}
+
+static int setup_dai(struct snd_soc_codec *codec,
+		     struct mc_asoc_data *mc_asoc, int id, int mode, int dir)
+{
+	struct mcdrv_dio_info dio;
+	struct mcdrv_dio_port *port = &dio.port[id];
+	struct mc_asoc_port_params *port_params = &mc_asoc->port;
+	struct mcdrv_path_info path, tmp_path;
+	u32 update = 0;
+	int ch, err, modify;
+
+	err = mc_control(MCDRV_GET_PATH, (unsigned long)&path, 0);
+	if (err < 0)
+		return err;
+
+	memset(&dio, 0, sizeof(struct mcdrv_dio_info));
+
+	if (port_params->stream == 0) {
+		port->dio_common.master_slave = port_params->master;
+		port->dio_common.auto_fs = MCDRV_AUTOFS_OFF;
+		port->dio_common.fs = port_params->rate;
+		port->dio_common.bck_fs = port_params->bckfs;
+		port->dio_common.interface = mode;
+		port->dio_common.bck_invert = port_params->inv;
+		port->dio_common.src_thru = port_params->srcthru;
+		if (mode == MCDRV_DIO_PCM)
+			port->dio_common.pcm_frame = port_params->format;
+		switch (id) {
+		case 0:
+			update |= MCDRV_MUSIC_COM_UPDATE_FLAG;
+			break;
+		case 1:
+			update |= MCDRV_EXT_COM_UPDATE_FLAG;
+			break;
+		case 3:
+			update |= MCDRV_HIFI_COM_UPDATE_FLAG;
+		default:
+			break;
+		}
+	}
+
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (mode == MCDRV_DIO_DA) {
+			port->dir.da_format.bit_sel = port_params->bits[dir];
+			port->dir.da_format.mode = port_params->format;
+		} else {
+			port->dir.pcm_format.mono = port_params->pcm_mono[dir];
+			port->dir.pcm_format.order =
+			    port_params->pcm_order[dir];
+			port->dir.pcm_format.law = port_params->pcm_law[dir];
+			port->dir.pcm_format.bit_sel = port_params->bits[dir];
+		}
+
+		switch (id) {
+		case 0:
+			update |= MCDRV_MUSIC_DIR_UPDATE_FLAG;
+			break;
+		case 3:
+			update |= MCDRV_HIFI_DIR_UPDATE_FLAG;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (dir == SNDRV_PCM_STREAM_CAPTURE) {
+		if (mode == MCDRV_DIO_DA) {
+			port->dit.da_format.bit_sel = port_params->bits[dir];
+			port->dit.da_format.mode = port_params->format;
+		} else {
+			port->dit.pcm_format.mono = port_params->pcm_mono[dir];
+			port->dit.pcm_format.order =
+			    port_params->pcm_order[dir];
+			port->dit.pcm_format.law = port_params->pcm_law[dir];
+			port->dit.pcm_format.bit_sel = port_params->bits[dir];
+		}
+
+		switch (id) {
+		case 0:
+			update |= MCDRV_MUSIC_DIT_UPDATE_FLAG;
+			break;
+		case 1:
+			update |= MCDRV_EXT_DIT_UPDATE_FLAG;
+			break;
+		case 3:
+			update |= MCDRV_HIFI_DIT_UPDATE_FLAG;
+			break;
+		default:
+			break;
+		}
+	}
+
+	modify = is_dio_modified(port, id, mode, update);
+	if (modify < 0)
+		return -EIO;
+	if (modify == 0)
+		return 0;
+
+	memcpy(&tmp_path, &path, sizeof(struct mcdrv_path_info));
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK || !port_params->stream) {
+		switch (id) {
+		case 0:
+			for (ch = 0; ch < MUSICOUT_PATH_CHANNELS; ch++) {
+				tmp_path.music_out[ch] &=
+				    ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.music_out[ch] |=
+				    MCDRV_D1SRC_MUSICIN_OFF;
+			}
+
+			for (ch = 0; ch < EXTOUT_PATH_CHANNELS; ch++) {
+				tmp_path.ext_out[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.ext_out[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+			}
+
+			for (ch = 0; ch < VBOXMIXIN_PATH_CHANNELS; ch++) {
+				tmp_path.vbox_mix_in[ch] &=
+				    ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.vbox_mix_in[ch] |=
+				    MCDRV_D1SRC_MUSICIN_OFF;
+			}
+
+			for (ch = 0; ch < AE_PATH_CHANNELS; ch++) {
+				tmp_path.ae0[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.ae0[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+				tmp_path.ae1[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.ae1[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+				tmp_path.ae2[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.ae2[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+				tmp_path.ae3[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.ae3[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+			}
+
+			for (ch = 0; ch < DAC0_PATH_CHANNELS; ch++) {
+				tmp_path.dac0[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.dac0[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+			}
+
+			for (ch = 0; ch < DAC1_PATH_CHANNELS; ch++) {
+				tmp_path.dac1[ch] &= ~MCDRV_D1SRC_MUSICIN_ON;
+				tmp_path.dac1[ch] |= MCDRV_D1SRC_MUSICIN_OFF;
+			}
+			break;
+		case 3:
+			for (ch = 0; ch < DAC0_PATH_CHANNELS; ch++) {
+				tmp_path.dac0[ch] &= ~MCDRV_D1SRC_HIFIIN_ON;
+				tmp_path.dac0[ch] |= MCDRV_D1SRC_HIFIIN_OFF;
+			}
+
+			for (ch = 0; ch < DAC1_PATH_CHANNELS; ch++) {
+				tmp_path.dac1[ch] &= ~MCDRV_D1SRC_HIFIIN_ON;
+				tmp_path.dac1[ch] |= MCDRV_D1SRC_HIFIIN_OFF;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (dir == SNDRV_PCM_STREAM_CAPTURE || !port_params->stream) {
+		switch (id) {
+		case 0:
+			for (ch = 0; ch < MUSICOUT_PATH_CHANNELS; ch++)
+				tmp_path.music_out[ch] = 0x00aaaaaa;
+			break;
+		case 1:
+			for (ch = 0; ch < EXTOUT_PATH_CHANNELS; ch++)
+				tmp_path.ext_out[ch] = 0x00aaaaaa;
+			break;
+		case 3:
+			for (ch = 0; ch < HIFIOUT_PATH_CHANNELS; ch++)
+				tmp_path.hifi_out[ch] = 0x00aaaaaa;
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (!memcmp(&tmp_path, &path, sizeof(struct mcdrv_path_info)))
+		modify = 0;
+	else {
+		err = mc_control(MCDRV_SET_PATH, (unsigned long)&tmp_path, 0);
+		if (err < 0)
+			return err;
+	}
+
+	err = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, update);
+	if (err < 0)
+		return err;
+
+	if (modify)
+		return connect_path(codec);
+
+	return 0;
+}
+
+static int mc_asoc_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_port_params *port;
+
+	if (!dai || !dai->codec || get_port_id(dai->id))
+		return -EINVAL;
+
+	mc_asoc = snd_soc_codec_get_drvdata(dai->codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	port = &mc_asoc->port;
+
+	if (div_id == MC_ASOC_BCLK_MULT) {
+		switch (div) {
+		case MC_ASOC_LRCK_X64:
+			port->bckfs = MCDRV_BCKFS_64;
+			break;
+		case MC_ASOC_LRCK_X48:
+			port->bckfs = MCDRV_BCKFS_48;
+			break;
+		case MC_ASOC_LRCK_X32:
+			port->bckfs = MCDRV_BCKFS_32;
+			break;
+		case MC_ASOC_LRCK_X512:
+			port->bckfs = MCDRV_BCKFS_512;
+			break;
+		case MC_ASOC_LRCK_X256:
+			port->bckfs = MCDRV_BCKFS_256;
+			break;
+		case MC_ASOC_LRCK_X192:
+			port->bckfs = MCDRV_BCKFS_192;
+			break;
+		case MC_ASOC_LRCK_X128:
+			port->bckfs = MCDRV_BCKFS_128;
+			break;
+		case MC_ASOC_LRCK_X96:
+			port->bckfs = MCDRV_BCKFS_96;
+			break;
+		case MC_ASOC_LRCK_X24:
+			port->bckfs = MCDRV_BCKFS_24;
+			break;
+		case MC_ASOC_LRCK_X16:
+			port->bckfs = MCDRV_BCKFS_16;
+			break;
+		default:
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int mc_asoc_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_port_params *port;
+
+	if (!dai || !dai->codec || get_port_id(dai->id))
+		return -EINVAL;
+
+	mc_asoc = snd_soc_codec_get_drvdata(dai->codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	port = &mc_asoc->port;
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		port->format = MCDRV_DAMODE_I2S;
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		port->format = MCDRV_DAMODE_TAILALIGN;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		port->format = MCDRV_DAMODE_HEADALIGN;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		port->format = MCDRV_PCM_SHORTFRAME;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		port->format = MCDRV_PCM_LONGFRAME;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		port->master = MCDRV_DIO_MASTER;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		port->master = MCDRV_DIO_SLAVE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		port->inv = MCDRV_BCLK_NORMAL;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		port->inv = MCDRV_BCLK_INVERT;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mc_asoc_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params,
+			     struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec;
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_port_params *port;
+	struct mcdrv_dio_path_info dio_path;
+	int dir = substream->stream;
+	int id, rate, err = 0;
+
+	if (!substream || !dai)
+		return -EINVAL;
+
+	id = get_port_id(dai->id);
+	if (id)
+		return -EINVAL;
+
+	codec = dai->codec;
+	if (!codec)
+		return -EINVAL;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	port = &mc_asoc->port;
+
+	switch (params_channels(params)) {
+	case 1:
+		port->pcm_mono[dir] = MCDRV_PCM_MONO;
+		port->channels = MCDRV_MUSIC_2CH;
+		break;
+	case 2:
+		port->channels = MCDRV_MUSIC_2CH;
+		port->pcm_mono[dir] = MCDRV_PCM_STEREO;
+		break;
+	case 4:
+		port->channels = MCDRV_MUSIC_4CH;
+		port->pcm_mono[dir] = MCDRV_PCM_STEREO;
+		break;
+	case 6:
+		port->channels = MCDRV_MUSIC_6CH;
+		port->pcm_mono[dir] = MCDRV_PCM_STEREO;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		port->bits[dir] = MCDRV_BITSEL_16;
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		port->bits[dir] = MCDRV_BITSEL_20;
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		port->bits[dir] = MCDRV_BITSEL_24;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (dir == SNDRV_PCM_STREAM_PLAYBACK) {
+		port->pcm_order[dir] = music_port_def.dir.pcm_format.order;
+		port->pcm_law[dir] = music_port_def.dir.pcm_format.law;
+	} else {
+		port->pcm_order[dir] = music_port_def.dit.pcm_format.order;
+		port->pcm_law[dir] = music_port_def.dit.pcm_format.law;
+	}
+
+	switch (params_rate(params)) {
+	case 8000:
+		rate = MCDRV_FS_8000;
+		break;
+	case 11025:
+		rate = MCDRV_FS_11025;
+		break;
+	case 16000:
+		rate = MCDRV_FS_16000;
+		break;
+	case 22050:
+		rate = MCDRV_FS_22050;
+		break;
+	case 32000:
+		rate = MCDRV_FS_32000;
+		break;
+	case 44100:
+		rate = MCDRV_FS_44100;
+		break;
+	case 48000:
+		rate = MCDRV_FS_48000;
+		break;
+	case 96000:
+		rate = MCDRV_FS_96000;
+		break;
+	case 192000:
+		rate = MCDRV_FS_192000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mutex_lock(&mc_asoc->mutex);
+
+	if (CAPTURE_PORT == CAPTURE_PORT_MUSIC)
+		if ((port->stream & ~(1 << dir)) && rate != port->rate) {
+			err = -EBUSY;
+			goto error;
+		}
+
+	port->rate = rate;
+
+	if (rate == MCDRV_FS_96000 || rate == MCDRV_FS_192000) {
+		struct mixer_path_ctl_info mixer_info;
+		int preset_idx;
+
+		if (get_mixer_path_ctl_info(codec, &mixer_info) < 0) {
+			err = -EIO;
+			goto error;
+		}
+
+		preset_idx = get_path_preset_idx(&mixer_info);
+		if (is_incall(preset_idx) || is_incommunication(preset_idx)) {
+			err = -EINVAL;
+			goto error;
+		}
+	}
+
+	if (rate == MCDRV_FS_96000 || rate == MCDRV_FS_192000) {
+		id = 3;
+	} else {
+		dio_path.music_ch = port->channels;
+		err = mc_control(MCDRV_SET_DIGITALIO_PATH,
+				 (unsigned long)&dio_path,
+				 MCDRV_MUSICNUM_UPDATE_FLAG);
+		if (err < 0) {
+			dev_err(codec->dev,
+				"Error in MCDRV_SET_DIGITALIO_PATH: %d\n", err);
+			goto error;
+		}
+
+		if (dir == SNDRV_PCM_STREAM_CAPTURE
+		    && CAPTURE_PORT == CAPTURE_PORT_EXT)
+			id = 1;
+	}
+
+	err = setup_dai(codec, mc_asoc, id, MCDRV_DIO_DA, dir);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in setup_dai: %d\n", err);
+		goto error;
+	}
+
+	port->stream |= 1 << dir;
+	mc_asoc_rate = rate;
+
+error:
+	mutex_unlock(&mc_asoc->mutex);
+
+	return err;
+}
+
+static int mc_asoc_hw_free(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec;
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_port_params *port;
+	int dir = substream->stream;
+
+	if (!substream || !dai || get_port_id(dai->id))
+		return -EINVAL;
+
+	codec = dai->codec;
+	if (!codec)
+		return -EINVAL;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	port = &mc_asoc->port;
+
+	mutex_lock(&mc_asoc->mutex);
+
+	if (port->stream & (1 << dir))
+		port->stream &= ~(1 << dir);
+
+	mutex_unlock(&mc_asoc->mutex);
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops mc_asoc_dai_ops[] = {
+	{
+	 .set_clkdiv = mc_asoc_set_clkdiv,
+	 .set_fmt = mc_asoc_set_fmt,
+	 .hw_params = mc_asoc_hw_params,
+	 .hw_free = mc_asoc_hw_free,
+	 },
+};
+
+static struct snd_soc_dai_driver mc_asoc_dai[] = {
+	{
+	 .name = MC_ASOC_NAME "-da0",
+	 .id = 1,
+	 .playback = {
+		      .stream_name = "Playback",
+		      .channels_min = 1,
+		      .channels_max = 6,
+		      .rates = MC_ASOC_RATE,
+		      .formats = MC_ASOC_FORMATS,
+		      },
+	 .capture = {
+		     .stream_name = "Capture",
+		     .channels_min = 1,
+		     .channels_max = 2,
+		     .rates = MC_ASOC_RATE,
+		     .formats = MC_ASOC_FORMATS,
+		     },
+	 .ops = &mc_asoc_dai_ops[0]
+	 },
+};
+
+/*
+ * Control interface
+ */
+/*
+ * Virtual register
+ *
+ * 16bit software registers are implemented for volumes and mute
+ * switches (as an exception, no mute switches for MIC and HP gain).
+ * Register contents are stored in codec's register cache.
+ *
+ *	15	14			8	7			0
+ *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ *	|swR|	volume-R		|swL|	volume-L		|
+ *	+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
+ */
+
+static unsigned int mc_asoc_read_reg(struct snd_soc_codec *codec,
+				     unsigned int reg)
+{
+	int ret;
+
+	if (!codec)
+		return -EINVAL;
+
+	ret = read_cache(codec, reg);
+	if (ret < 0)
+		return -EIO;
+
+	return (unsigned int)ret;
+}
+
+static int write_reg_vol(struct snd_soc_codec *codec, unsigned int reg,
+			 unsigned int value)
+{
+	struct mcdrv_vol_info vol;
+	struct mixer_path_ctl_info mixer;
+	int err, preset_idx;
+
+	err = snd_soc_cache_write(codec, reg, value);
+	if (err < 0)
+		dev_err(codec->dev, "Cache write to 0x%x failed: %d\n", reg,
+			err);
+
+	if (get_mixer_path_ctl_info(codec, &mixer) < 0)
+		return -EIO;
+
+	preset_idx = get_path_preset_idx(&mixer);
+	if (preset_idx < 0 || preset_idx > PRESET_PATH_N)
+		return -EIO;
+
+	memset(&vol, 0, sizeof(struct mcdrv_vol_info));
+
+	switch (reg) {
+	case MC_ASOC_AVOL_SP_GAIN:
+		if (!mc_asoc_ver_id) {
+			vreg_map[MC_ASOC_AVOL_SP].volmap = volmap_sp[value];
+			reg = MC_ASOC_AVOL_SP;
+		} else
+			return 0;
+		break;
+	case MC_ASOC_DVOL_MASTER:
+		if (mc_asoc_audio_play_port == LIN1)
+			reg = MC_ASOC_DVOL_ADIF1IN;
+		else
+			reg = MC_ASOC_DVOL_MUSICIN;
+		break;
+	case MC_ASOC_DVOL_VOICE:
+		if (is_incall(preset_idx)) {
+			reg = MC_ASOC_DVOL_VOICEIN;
+			if (mc_asoc_voice_port == LIN1_LOUT1
+			    || mc_asoc_voice_port == LIN1_LOUT2)
+				reg = MC_ASOC_AVOL_LINEIN1;
+		} else
+			return 0;
+		break;
+	case MC_ASOC_DVOL_APLAY_A:
+		reg = MC_ASOC_AVOL_MIC1;
+		err = set_vol_info(codec, &vol, reg, &mixer, preset_idx);
+		if (err < 0)
+			return err;
+
+		reg = MC_ASOC_AVOL_MIC2;
+		err = set_vol_info(codec, &vol, reg, &mixer, preset_idx);
+		if (err < 0)
+			return err;
+
+		reg = MC_ASOC_AVOL_MIC3;
+		err = set_vol_info(codec, &vol, reg, &mixer, preset_idx);
+		if (err < 0)
+			return err;
+
+		reg = MC_ASOC_AVOL_MIC4;
+		err = set_vol_info(codec, &vol, reg, &mixer, preset_idx);
+		if (err < 0)
+			return err;
+
+		reg = MC_ASOC_AVOL_LINEIN1;
+		break;
+	case MC_ASOC_DVOL_APLAY_D:
+		reg = MC_ASOC_DVOL_ADIF1IN;
+		break;
+	case MC_ASOC_VOICE_RECORDING:
+		if (is_incall(preset_idx)) {
+			reg = MC_ASOC_DVOL_VOICEOUT;
+			if (mc_asoc_voice_port == LIN1_LOUT1)
+				reg = MC_ASOC_DVOL_DAC0OUT;
+			else if (mc_asoc_voice_port == LIN1_LOUT2)
+				reg = MC_ASOC_DVOL_DAC1OUT;
+		} else if (is_incommunication(preset_idx))
+			reg = MC_ASOC_DVOL_VOICEOUT;
+		else
+			return 0;
+		break;
+	default:
+		break;
+	}
+
+	err = set_vol_info(codec, &vol, reg, &mixer, preset_idx);
+	if (err < 0)
+		return err;
+
+	err = mc_control(MCDRV_SET_VOLUME, (unsigned long)&vol, 0);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in MCDRV_SET_VOLUME: %d\n", err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void auto_powerdown(struct snd_soc_codec *codec)
+{
+#if (AUTO_POWEROFF == AUTO_POWEROFF_ON)
+	struct mixer_path_ctl_info mixer;
+	u8 aec[] = {
+		0x41, 0x45, 0x43,
+		0x05,
+		0, 0, 0, 60,
+		0x00,
+		253,
+		0,
+		0,
+		/*      D7:     */
+		0x44, 0x37,
+		0, 0, 0, 50,
+		/*      AudioEngine:16  */
+		0x02, 0x00, 0x00, 0x00,
+		0, 0, 0, 8,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		/*      V-BOX:23        */
+		0x03, 0x00, 0x00, 0x00,
+		0, 0, 0, 15,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		0,
+		/*      E-DSP:11        */
+		0x07, 0x00, 0x00, 0x00,
+		0, 0, 0, 3,
+		0,
+		0,
+		0,
+	};
+
+	get_mixer_path_ctl_info(codec, &mixer);
+	if (!mixer.audio_mode_play && !mixer.audio_mode_cap
+	    && !mixer.mainmic_play && !mixer.submic_play
+	    && !mixer.msmic_play && !mixer.hsmic_play
+	    && !mixer.btmic_play && !mixer.lin1_play && !mixer.dtmf_control)
+		mc_control(MCDRV_SET_DSP, (unsigned long)aec, sizeof(aec));
+#endif
+}
+
+static void del_dsp_param(struct mc_asoc_data *mc_asoc)
+{
+	struct mc_asoc_dsp_params *dsp_params, *next;
+	int i, j;
+
+	for (i = 0; i <= DSP_PRM_VC_2MIC; i++) {
+		for (j = 0; j <= DSP_PRM_USER; j++) {
+			kfree(mc_asoc->params_store[i][j].pab_param);
+
+			dsp_params = mc_asoc->params_store[i][j].next;
+			while (dsp_params) {
+				kfree(dsp_params->pab_param);
+				next = dsp_params->next;
+				kfree(dsp_params);
+				dsp_params = next;
+			}
+
+			mc_asoc->params_store[i][j].pab_param = NULL;
+			mc_asoc->params_store[i][j].size = 0;
+			mc_asoc->params_store[i][j].next = NULL;
+		}
+	}
+}
+
+static int set_audio_mode_play(struct snd_soc_codec *codec, unsigned int value)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_port_params *port;
+	int ret;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	port = &mc_asoc->port;
+	if (value > 1) {
+		u8 rate = port->rate;
+		if (port->stream
+		    && (rate == MCDRV_FS_96000 || rate == MCDRV_FS_192000))
+			return -EINVAL;
+	}
+
+	ret = snd_soc_cache_write(codec, MC_ASOC_AUDIO_MODE_PLAY, value);
+	if (ret < 0)
+		return ret;
+
+	if (!value)
+		del_dsp_param(mc_asoc);
+
+	ret = connect_path(codec);
+	if (!value)
+		auto_powerdown(codec);
+
+	return ret;
+}
+
+static int set_audio_mode_cap(struct snd_soc_codec *codec, unsigned int value)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_port_params *port;
+	int ret;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	port = &mc_asoc->port;
+	if (value > 1) {
+		u8 rate = port->rate;
+		if (port->stream
+		    && (rate == MCDRV_FS_96000 || rate == MCDRV_FS_192000))
+			return -EINVAL;
+	}
+
+	ret = snd_soc_cache_write(codec, MC_ASOC_AUDIO_MODE_CAP, value);
+	if (ret < 0)
+		return ret;
+
+	if (!value)
+		del_dsp_param(mc_asoc);
+
+	ret = connect_path(codec);
+	if (!value)
+		auto_powerdown(codec);
+
+	return ret;
+}
+
+static int set_incall_mic(struct snd_soc_codec *codec,
+			  unsigned int reg, unsigned int value)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mc_asoc_dsp_params *dsp_params;
+	int ret;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	ret = snd_soc_cache_write(codec, reg, value);
+	if (ret < 0)
+		return ret;
+
+	if (value == MC_ASOC_INCALL_MIC_MAINMIC
+	    || value == MC_ASOC_INCALL_MIC_SUBMIC)
+		dsp_params =
+		    &mc_asoc->params_store[DSP_PRM_VC_1MIC][DSP_PRM_BASE];
+	else
+		dsp_params =
+		    &mc_asoc->params_store[DSP_PRM_VC_2MIC][DSP_PRM_BASE];
+
+	while (dsp_params) {
+		if (dsp_params->size > 0) {
+			ret = mc_control(MCDRV_SET_DSP,
+					 (unsigned long)dsp_params->pab_param,
+					 dsp_params->size);
+			if (ret < 0)
+				return ret;
+		}
+
+		dsp_params = dsp_params->next;
+	}
+
+	return connect_path(codec);
+}
+
+static int set_ain_playback(struct snd_soc_codec *codec,
+			    unsigned int reg, unsigned int value)
+{
+	int audio_mode, audio_mode_cap, ret;
+
+	audio_mode_cap = read_cache(codec, MC_ASOC_AUDIO_MODE_CAP);
+	if (audio_mode_cap < 0)
+		return -EIO;
+
+	audio_mode = read_cache(codec, MC_ASOC_AUDIO_MODE_PLAY);
+	if (audio_mode < 0)
+		return -EIO;
+
+	ret = snd_soc_cache_write(codec, reg, value);
+	if (ret < 0)
+		return ret;
+
+	if (audio_mode == MC_ASOC_AUDIO_MODE_INCALL
+	    || audio_mode == MC_ASOC_AUDIO_MODE_INCALL2
+	    || audio_mode == MC_ASOC_AUDIO_MODE_AUDIO_INCALL
+	    || audio_mode == MC_ASOC_AUDIO_MODE_AUDIO_INCALL2) {
+		if (audio_mode_cap == MC_ASOC_AUDIO_MODE_INCALL
+		    || audio_mode_cap == MC_ASOC_AUDIO_MODE_AUDIO_INCALL)
+			return 0;
+	}
+
+	if ((audio_mode == MC_ASOC_AUDIO_MODE_INCOMM
+	     || audio_mode == MC_ASOC_AUDIO_MODE_INCOMM2)
+	    && audio_mode_cap == MC_ASOC_AUDIO_MODE_INCOMM)
+		return 0;
+
+	ret = connect_path(codec);
+	if (!value)
+		auto_powerdown(codec);
+
+	return ret;
+}
+
+static int set_dtmf_control(struct snd_soc_codec *codec,
+			    unsigned int reg, unsigned int value)
+{
+	int ret;
+
+	ret = snd_soc_cache_write(codec, reg, value);
+	if (ret < 0)
+		return ret;
+
+	ret = connect_path(codec);
+	if (!value)
+		auto_powerdown(codec);
+
+	return ret;
+}
+
+static int set_dtmf_output(struct snd_soc_codec *codec,
+			   unsigned int reg, unsigned int value)
+{
+	int ret;
+
+	ret = snd_soc_cache_write(codec, reg, value);
+	if (ret < 0)
+		return ret;
+
+	return connect_path(codec);
+}
+
+static int set_switch_clock(struct snd_soc_codec *codec,
+			    unsigned int reg, unsigned int value)
+{
+	int ret;
+
+	ret = mc_control(MCDRV_SET_CLOCKSW, value, 0);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_master_slave(struct snd_soc_codec *codec,
+			    unsigned int reg, unsigned int value, u8 port)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	dio.port[port].dio_common.master_slave = value;
+	if (port == 1)
+		flag = MCDRV_EXT_COM_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_COM_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_rate(struct snd_soc_codec *codec,
+		    unsigned int reg, unsigned int value, u8 port)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	dio.port[port].dio_common.fs = value;
+	if (port == 1)
+		flag = MCDRV_EXT_COM_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_COM_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_bitclock_rate(struct snd_soc_codec *codec,
+			     unsigned int reg, unsigned int value, u8 port)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	dio.port[port].dio_common.bck_fs = value;
+	if (port == 1)
+		flag = MCDRV_EXT_COM_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_COM_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_interface(struct snd_soc_codec *codec,
+			 unsigned int reg, unsigned int value, u8 port)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	dio.port[port].dio_common.interface = value;
+	if (port == 1)
+		flag = MCDRV_EXT_COM_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_COM_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_bitclock_invert(struct snd_soc_codec *codec,
+			       unsigned int reg, unsigned int value, u8 port)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	dio.port[port].dio_common.bck_invert = value;
+	if (port == 1)
+		flag = MCDRV_EXT_COM_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_COM_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_da_bit_width(struct snd_soc_codec *codec,
+			    unsigned int reg, unsigned int value,
+			    u8 port, u8 in_out)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	if (!in_out)
+		dio.port[port].dir.da_format.bit_sel = value;
+	else
+		dio.port[port].dit.da_format.bit_sel = value;
+
+	if (port == 1)
+		flag = MCDRV_EXT_DIR_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_DIR_UPDATE_FLAG
+		    | MCDRV_VOICE_DIT_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_da_format(struct snd_soc_codec *codec,
+			 unsigned int reg, unsigned int value,
+			 u8 port, u8 in_out)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	if (!in_out)
+		dio.port[port].dir.da_format.mode = value;
+	else
+		dio.port[port].dit.da_format.mode = value;
+
+	if (port == 1)
+		flag = MCDRV_EXT_DIR_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_DIR_UPDATE_FLAG
+		    | MCDRV_VOICE_DIT_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_pcm_mono_stereo(struct snd_soc_codec *codec,
+			       unsigned int reg, unsigned int value,
+			       u8 port, u8 in_out)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	if (!in_out)
+		dio.port[port].dir.pcm_format.mono = value;
+	else
+		dio.port[port].dit.pcm_format.mono = value;
+
+	if (port == 1)
+		flag = MCDRV_EXT_DIR_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_DIR_UPDATE_FLAG
+		    | MCDRV_VOICE_DIT_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_pcm_bit_order(struct snd_soc_codec *codec,
+			     unsigned int reg, unsigned int value,
+			     u8 port, u8 in_out)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	if (!in_out)
+		dio.port[port].dir.pcm_format.order = value;
+	else
+		dio.port[port].dit.pcm_format.order = value;
+
+	if (port == 1)
+		flag = MCDRV_EXT_DIR_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_DIR_UPDATE_FLAG
+		    | MCDRV_VOICE_DIT_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_pcm_format(struct snd_soc_codec *codec,
+			  unsigned int reg, unsigned int value,
+			  u8 port, u8 in_out)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	if (!in_out)
+		dio.port[port].dir.pcm_format.law = value;
+	else
+		dio.port[port].dit.pcm_format.law = value;
+
+	if (port == 1)
+		flag = MCDRV_EXT_DIR_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_DIR_UPDATE_FLAG
+		    | MCDRV_VOICE_DIT_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_pcm_bit_width(struct snd_soc_codec *codec,
+			     unsigned int reg, unsigned int value,
+			     u8 port, u8 in_out)
+{
+	struct mcdrv_dio_info dio;
+	u32 flag;
+	int ret;
+
+	ret = mc_control(MCDRV_GET_DIGITALIO, (unsigned long)&dio, 0);
+	if (ret < 0)
+		return ret;
+
+	if (!in_out)
+		dio.port[port].dir.pcm_format.bit_sel = value;
+	else
+		dio.port[port].dit.pcm_format.bit_sel = value;
+
+	if (port == 1)
+		flag = MCDRV_EXT_DIR_UPDATE_FLAG | MCDRV_EXT_DIT_UPDATE_FLAG;
+	else
+		flag = MCDRV_VOICE_DIR_UPDATE_FLAG
+		    | MCDRV_VOICE_DIT_UPDATE_FLAG;
+
+	ret = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_phys_port(struct snd_soc_codec *codec,
+			 unsigned int reg, unsigned int value, u8 port)
+{
+	struct mcdrv_dio_path_info info;
+	int ret;
+
+	info.phys_port[port] = value;
+	ret =
+	    mc_control(MCDRV_SET_DIGITALIO_PATH, (unsigned long)&info,
+		       1 << port);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int set_swap(struct snd_soc_codec *codec,
+		    unsigned int reg, unsigned int value,
+		    size_t offset, u32 flag)
+{
+	struct mcdrv_swap_info swap;
+	int ret;
+
+	*(u8 *) ((void *)&swap + offset) = value;
+	ret = mc_control(MCDRV_SET_SWAP, (unsigned long)&swap, flag);
+	if (ret < 0)
+		return ret;
+
+	return snd_soc_cache_write(codec, reg, value);
+}
+
+static int mc_asoc_write_reg(struct snd_soc_codec *codec,
+			     unsigned int reg, unsigned int value)
+{
+	int err = 0;
+
+	if (!codec)
+		return -EINVAL;
+
+	if (reg <= MC_ASOC_N_VOL_REG) {
+		switch (reg) {
+		case MC_ASOC_DVOL_MUSICIN:
+		case MC_ASOC_DVOL_EXTIN:
+		case MC_ASOC_DVOL_VOICEIN:
+		case MC_ASOC_DVOL_REFIN:
+		case MC_ASOC_DVOL_ADIF0IN:
+		case MC_ASOC_DVOL_ADIF1IN:
+		case MC_ASOC_DVOL_ADIF2IN:
+		case MC_ASOC_DVOL_MUSICOUT:
+		case MC_ASOC_DVOL_EXTOUT:
+		case MC_ASOC_DVOL_VOICEOUT:
+		case MC_ASOC_DVOL_REFOUT:
+		case MC_ASOC_DVOL_DAC0OUT:
+		case MC_ASOC_DVOL_DAC1OUT:
+		case MC_ASOC_DVOL_DPATHDA:
+		case MC_ASOC_DVOL_DPATHAD:
+		case MC_ASOC_DVOL_APLAY_D:
+			if (((value >> 8) & 0x7f) > 114 || (value & 0x7f) > 114)
+				return -EINVAL;
+			break;
+		case MC_ASOC_AVOL_LINEIN1:
+		case MC_ASOC_AVOL_MIC1:
+		case MC_ASOC_AVOL_MIC2:
+		case MC_ASOC_AVOL_MIC3:
+		case MC_ASOC_AVOL_MIC4:
+		case MC_ASOC_DVOL_APLAY_A:
+			if (((value >> 8) & 0x7f) > 63 || (value & 0x7f) > 63)
+				return -EINVAL;
+			break;
+		case MC_ASOC_AVOL_HP:
+			if (((value >> 8) & 0x7f) > 127 || (value & 0x7f) > 127)
+				return -EINVAL;
+			break;
+		case MC_ASOC_AVOL_SP:
+			if (((value >> 8) & 0x7f) > 127 || (value & 0x7f) > 127)
+				return -EINVAL;
+			break;
+		case MC_ASOC_AVOL_RC:
+			if (((value >> 8) & 0x7f) > 111 || (value & 0x7f) > 111)
+				return -EINVAL;
+			break;
+		case MC_ASOC_AVOL_LINEOUT1:
+		case MC_ASOC_AVOL_LINEOUT2:
+			if (((value >> 8) & 0x7f) > 119 || (value & 0x7f) > 119)
+				return -EINVAL;
+			break;
+		case MC_ASOC_AVOL_SP_GAIN:
+			if (((value >> 8) & 0x7f) > 4 || (value & 0x7f) > 4)
+				return -EINVAL;
+			break;
+		case MC_ASOC_DVOL_MASTER:
+		case MC_ASOC_DVOL_VOICE:
+			if (((value >> 8) & 0x7f) > 75 || (value & 0x7f) > 75)
+				return -EINVAL;
+			break;
+		case MC_ASOC_VOICE_RECORDING:
+			if ((value & 0x7f) > 1)
+				return -EINVAL;
+			break;
+		}
+
+		if (!err)
+			err = write_reg_vol(codec, reg, value);
+	} else {
+		switch (reg) {
+		case MC_ASOC_AUDIO_MODE_PLAY:
+			err = set_audio_mode_play(codec, value);
+			break;
+		case MC_ASOC_AUDIO_MODE_CAP:
+			err = set_audio_mode_cap(codec, value);
+			break;
+		case MC_ASOC_OUTPUT_PATH:
+			err = snd_soc_cache_write(codec, reg, value);
+			break;
+		case MC_ASOC_INPUT_PATH:
+			err = snd_soc_cache_write(codec, reg, value);
+			break;
+		case MC_ASOC_INCALL_MIC_SP:
+		case MC_ASOC_INCALL_MIC_RC:
+		case MC_ASOC_INCALL_MIC_HP:
+		case MC_ASOC_INCALL_MIC_LO1:
+		case MC_ASOC_INCALL_MIC_LO2:
+			err = set_incall_mic(codec, reg, value);
+			break;
+		case MC_ASOC_MAINMIC_PLAYBACK_PATH:
+		case MC_ASOC_SUBMIC_PLAYBACK_PATH:
+		case MC_ASOC_2MIC_PLAYBACK_PATH:
+		case MC_ASOC_HSMIC_PLAYBACK_PATH:
+		case MC_ASOC_BTMIC_PLAYBACK_PATH:
+		case MC_ASOC_LIN1_PLAYBACK_PATH:
+			err = set_ain_playback(codec, reg, value);
+			break;
+		case MC_ASOC_PARAMETER_SETTING:
+			break;
+		case MC_ASOC_DTMF_CONTROL:
+			err = set_dtmf_control(codec, reg, value);
+			break;
+		case MC_ASOC_DTMF_OUTPUT:
+			err = set_dtmf_output(codec, reg, value);
+			break;
+		case MC_ASOC_SWITCH_CLOCK:
+			err = set_switch_clock(codec, reg, value);
+			break;
+		case MC_ASOC_EXT_MASTERSLAVE:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_master_slave(codec, reg, value,
+						       PORT_EXT);
+			break;
+		case MC_ASOC_EXT_RATE:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_rate(codec, reg, value, PORT_EXT);
+			break;
+		case MC_ASOC_EXT_BITCLOCK_RATE:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_bitclock_rate(codec, reg, value,
+							PORT_EXT);
+			break;
+		case MC_ASOC_EXT_INTERFACE:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_interface(codec, reg, value,
+						    PORT_EXT);
+			break;
+		case MC_ASOC_EXT_BITCLOCK_INVERT:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_bitclock_invert(codec, reg, value,
+							  PORT_EXT);
+			break;
+		case MC_ASOC_EXT_INPUT_DA_BIT_WIDTH:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_da_bit_width(codec, reg, value,
+						       PORT_EXT, 0);
+			break;
+		case MC_ASOC_EXT_INPUT_DA_FORMAT:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_da_format(codec, reg, value,
+						    PORT_EXT, 0);
+			break;
+		case MC_ASOC_EXT_INPUT_PCM_MONOSTEREO:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_mono_stereo(codec, reg, value,
+							  PORT_EXT, 0);
+			break;
+		case MC_ASOC_EXT_INPUT_PCM_BIT_ORDER:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_bit_order(codec, reg, value,
+							PORT_EXT, 0);
+			break;
+		case MC_ASOC_EXT_INPUT_PCM_FORMAT:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_format(codec, reg, value,
+						     PORT_EXT, 0);
+			break;
+		case MC_ASOC_EXT_INPUT_PCM_BIT_WIDTH:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_bit_width(codec, reg, value,
+							PORT_EXT, 0);
+			break;
+		case MC_ASOC_EXT_OUTPUT_DA_BIT_WIDTH:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_da_bit_width(codec, reg, value,
+						       PORT_EXT, 1);
+			break;
+		case MC_ASOC_EXT_OUTPUT_DA_FORMAT:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_da_format(codec, reg, value,
+						    PORT_EXT, 1);
+			break;
+		case MC_ASOC_EXT_OUTPUT_PCM_MONOSTEREO:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_mono_stereo(codec, reg, value,
+							  PORT_EXT, 1);
+			break;
+		case MC_ASOC_EXT_OUTPUT_PCM_BIT_ORDER:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_bit_order(codec, reg, value,
+							PORT_EXT, 1);
+			break;
+		case MC_ASOC_EXT_OUTPUT_PCM_FORMAT:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_format(codec, reg, value,
+						     PORT_EXT, 1);
+			break;
+		case MC_ASOC_EXT_OUTPUT_PCM_BIT_WIDTH:
+			if (CAPTURE_PORT != CAPTURE_PORT_EXT)
+				err = set_pcm_bit_width(codec, reg, value,
+							PORT_EXT, 1);
+			break;
+		case MC_ASOC_VOICE_MASTERSLAVE:
+			err = set_master_slave(codec, reg, value, PORT_VOICE);
+			break;
+		case MC_ASOC_VOICE_RATE:
+			err = set_rate(codec, reg, value, PORT_VOICE);
+			break;
+		case MC_ASOC_VOICE_BITCLOCK_RATE:
+			err = set_bitclock_rate(codec, reg, value, PORT_VOICE);
+			break;
+		case MC_ASOC_VOICE_INTERFACE:
+			err = set_interface(codec, reg, value, PORT_VOICE);
+			break;
+		case MC_ASOC_VOICE_BITCLOCK_INVERT:
+			err = set_bitclock_invert(codec, reg, value,
+						  PORT_VOICE);
+			break;
+		case MC_ASOC_VOICE_INPUT_DA_BIT_WIDTH:
+			err = set_da_bit_width(codec, reg, value,
+					       PORT_VOICE, 0);
+			break;
+		case MC_ASOC_VOICE_INPUT_DA_FORMAT:
+			err = set_da_format(codec, reg, value, PORT_VOICE, 0);
+			break;
+		case MC_ASOC_VOICE_INPUT_PCM_MONOSTEREO:
+			err = set_pcm_mono_stereo(codec, reg, value,
+						  PORT_VOICE, 0);
+			break;
+		case MC_ASOC_VOICE_INPUT_PCM_BIT_ORDER:
+			err = set_pcm_bit_order(codec, reg, value,
+						PORT_VOICE, 0);
+			break;
+		case MC_ASOC_VOICE_INPUT_PCM_FORMAT:
+			err = set_pcm_format(codec, reg, value, PORT_VOICE, 0);
+			break;
+		case MC_ASOC_VOICE_INPUT_PCM_BIT_WIDTH:
+			err = set_pcm_bit_width(codec, reg, value,
+						PORT_VOICE, 0);
+			break;
+		case MC_ASOC_VOICE_OUTPUT_DA_BIT_WIDTH:
+			err = set_da_bit_width(codec, reg, value,
+					       PORT_VOICE, 1);
+			break;
+		case MC_ASOC_VOICE_OUTPUT_DA_FORMAT:
+			err = set_da_format(codec, reg, value, PORT_VOICE, 1);
+			break;
+		case MC_ASOC_VOICE_OUTPUT_PCM_MONOSTEREO:
+			err = set_pcm_mono_stereo(codec, reg, value,
+						  PORT_VOICE, 1);
+			break;
+		case MC_ASOC_VOICE_OUTPUT_PCM_BIT_ORDER:
+			err = set_pcm_bit_order(codec, reg, value,
+						PORT_VOICE, 1);
+			break;
+		case MC_ASOC_VOICE_OUTPUT_PCM_FORMAT:
+			err = set_pcm_format(codec, reg, value, PORT_VOICE, 1);
+			break;
+		case MC_ASOC_VOICE_OUTPUT_PCM_BIT_WIDTH:
+			err = set_pcm_bit_width(codec, reg, value,
+						PORT_VOICE, 1);
+			break;
+		case MC_ASOC_MUSIC_PHYSICAL_PORT:
+			err = set_phys_port(codec, reg, value, PORT_MUSIC);
+			break;
+		case MC_ASOC_EXT_PHYSICAL_PORT:
+			err = set_phys_port(codec, reg, value, PORT_EXT);
+			break;
+		case MC_ASOC_VOICE_PHYSICAL_PORT:
+			err = set_phys_port(codec, reg, value, PORT_VOICE);
+			break;
+		case MC_ASOC_HIFI_PHYSICAL_PORT:
+			err = set_phys_port(codec, reg, value, PORT_HIFI);
+			break;
+		case MC_ASOC_ADIF0_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info, adif0),
+				       MCDRV_SWAP_ADIF0_UPDATE_FLAG);
+			break;
+		case MC_ASOC_ADIF1_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info, adif1),
+				       MCDRV_SWAP_ADIF1_UPDATE_FLAG);
+			break;
+		case MC_ASOC_ADIF2_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info, adif2),
+				       MCDRV_SWAP_ADIF2_UPDATE_FLAG);
+			break;
+		case MC_ASOC_DAC0_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info, dac0),
+				       MCDRV_SWAP_DAC0_UPDATE_FLAG);
+			break;
+		case MC_ASOC_DAC1_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info, dac1),
+				       MCDRV_SWAP_DAC1_UPDATE_FLAG);
+			break;
+		case MC_ASOC_MUSIC_OUT0_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						music_out0),
+				       MCDRV_SWAP_MUSICOUT0_UPDATE_FLAG);
+			break;
+		case MC_ASOC_MUSIC_IN0_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						music_in0),
+				       MCDRV_SWAP_MUSICIN0_UPDATE_FLAG);
+			break;
+		case MC_ASOC_MUSIC_IN1_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						music_in1),
+				       MCDRV_SWAP_MUSICIN1_UPDATE_FLAG);
+			break;
+		case MC_ASOC_MUSIC_IN2_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						music_in2),
+				       MCDRV_SWAP_MUSICIN2_UPDATE_FLAG);
+			break;
+		case MC_ASOC_EXT_IN_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info, ext_in),
+				       MCDRV_SWAP_EXTIN_UPDATE_FLAG);
+			break;
+		case MC_ASOC_VOICE_IN_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						voice_in),
+				       MCDRV_SWAP_VOICEIN_UPDATE_FLAG);
+			break;
+		case MC_ASOC_MUSIC_OUT1_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						music_out1),
+				       MCDRV_SWAP_MUSICOUT1_UPDATE_FLAG);
+			break;
+		case MC_ASOC_MUSIC_OUT2_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						music_out2),
+				       MCDRV_SWAP_MUSICOUT2_UPDATE_FLAG);
+			break;
+		case MC_ASOC_EXT_OUT_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						ext_out),
+				       MCDRV_SWAP_EXTOUT_UPDATE_FLAG);
+			break;
+		case MC_ASOC_VOICE_OUT_SWAP:
+			err = set_swap(codec, reg, value,
+				       offsetof(struct mcdrv_swap_info,
+						voice_out),
+				       MCDRV_SWAP_VOICEOUT_UPDATE_FLAG);
+			break;
+		case MC_ASOC_ADIF0_SOURCE:
+		case MC_ASOC_ADIF1_SOURCE:
+		case MC_ASOC_ADIF2_SOURCE:
+			err = snd_soc_cache_write(codec, reg, value);
+			if (err < 0)
+				break;
+
+			err = connect_path(codec);
+			break;
+		case MC_ASOC_MAIN_MIC:
+			mc_asoc_main_mic = value;
+			snd_soc_cache_write(codec, reg, value);
+			break;
+		case MC_ASOC_SUB_MIC:
+			mc_asoc_sub_mic = value;
+			snd_soc_cache_write(codec, reg, value);
+			break;
+		case MC_ASOC_HS_MIC:
+			mc_asoc_hs_mic = value;
+			snd_soc_cache_write(codec, reg, value);
+			break;
+#ifdef MC_ASOC_TEST
+		case MC_ASOC_MIC1_BIAS:
+			mc_asoc_mic1_bias = value;
+			snd_soc_cache_write(codec, reg, value);
+			err = connect_path(codec);
+			break;
+		case MC_ASOC_MIC2_BIAS:
+			mc_asoc_mic2_bias = value;
+			snd_soc_cache_write(codec, reg, value);
+			err = connect_path(codec);
+			break;
+		case MC_ASOC_MIC3_BIAS:
+			mc_asoc_mic3_bias = value;
+			snd_soc_cache_write(codec, reg, value);
+			err = connect_path(codec);
+			break;
+		case MC_ASOC_MIC4_BIAS:
+			mc_asoc_mic4_bias = value;
+			snd_soc_cache_write(codec, reg, value);
+			err = connect_path(codec);
+			break;
+#endif
+		default:
+			err = -EINVAL;
+			break;
+		}
+	}
+
+	return err;
+}
+
+static const struct snd_soc_dapm_widget mc_asoc_widgets[] = {
+	SND_SOC_DAPM_DAC("DAC DUMMY", "DAC Playback", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("ADC DUMMY", "ADC Capture", SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_INPUT("INPUT DUMMY"),
+	SND_SOC_DAPM_OUTPUT("OUTPUT DUMMY"),
+};
+
+static const struct snd_soc_dapm_widget mc_asoc_widgets_headset[] = {
+	SND_SOC_DAPM_OUTPUT("HPOUTL"),
+	SND_SOC_DAPM_OUTPUT("HPOUTR"),
+	SND_SOC_DAPM_INPUT("AMIC1"),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route mc_asoc_intercon[] = {
+	{"OUTPUT DUMMY", NULL, "DAC DUMMY"},
+	{"ADC DUMMY", NULL, "INPUT DUMMY"}
+};
+
+static const struct snd_soc_dapm_route mc_asoc_intercon_headset[] = {
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Headphone Jack", NULL, "HPOUTR"},
+	{"Mic Jack", NULL, "AMIC1"},
+};
+
+static int mc_asoc_add_widgets(struct snd_soc_codec *codec)
+{
+	int err;
+
+	if (!codec)
+		return -EINVAL;
+
+	err = snd_soc_dapm_new_controls(&codec->dapm, mc_asoc_widgets,
+					ARRAY_SIZE(mc_asoc_widgets));
+	if (err < 0)
+		return err;
+
+	err = snd_soc_dapm_add_routes(&codec->dapm, mc_asoc_intercon,
+				      ARRAY_SIZE(mc_asoc_intercon));
+	if (err < 0)
+		return err;
+
+	err = snd_soc_dapm_new_controls(&codec->dapm, mc_asoc_widgets_headset,
+					ARRAY_SIZE(mc_asoc_widgets_headset));
+	if (err < 0)
+		return err;
+
+	err = snd_soc_dapm_add_routes(&codec->dapm, mc_asoc_intercon_headset,
+				      ARRAY_SIZE(mc_asoc_intercon_headset));
+	if (err < 0)
+		return err;
+
+	return snd_soc_dapm_new_widgets(&codec->dapm);
+}
+
+static struct input_dev *inp_dev;
+
+static struct snd_soc_jack hs_jack;
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+	{
+	 .pin = "Mic Jack",
+	 .mask = SND_JACK_MICROPHONE,
+	 },
+	{
+	 .pin = "Headphone Jack",
+	 .mask = SND_JACK_HEADPHONE,
+	 },
+};
+
+static struct workqueue_struct *mb4_workq;
+static struct delayed_work delayed_work;
+
+static void mb4_work(struct work_struct *work)
+{
+	connect_path(mc_asoc_codec);
+}
+
+static void headset_detect_callback(u32 flags, struct mcdrv_hsdet_res *res)
+{
+	struct mcdrv_hsdet_info info;
+	u8 hpimpclass = mc_asoc_hpimpclass;
+	u8 en_plug_det_db, en_mic_det, en_dly_key_off, en_dly_key_on;
+	u8 en_key_off, en_key_on, hs_det_dbnc, dbnc_num_plug;
+	u8 key0_on_dly_tim, key1_on_dly_tim, key2_on_dly_tim;
+	u8 key0_on_dly_tim2, key1_on_dly_tim2, key2_on_dly_tim2;
+	u8 current_en_plug_det_db;
+	int err;
+
+	if (!mc_asoc_suspended) {
+		en_plug_det_db = hsdet_info_def.en_plug_det_db;
+		en_mic_det = hsdet_info_def.en_mic_det;
+		en_dly_key_off = hsdet_info_def.en_dly_key_off;
+		en_dly_key_on = hsdet_info_def.en_dly_key_on;
+		en_key_off = hsdet_info_def.en_key_off;
+		en_key_on = hsdet_info_def.en_key_on;
+		key0_on_dly_tim = hsdet_info_def.key0_on_dly_tim;
+		key1_on_dly_tim = hsdet_info_def.key1_on_dly_tim;
+		key2_on_dly_tim = hsdet_info_def.key2_on_dly_tim;
+		key0_on_dly_tim2 = hsdet_info_def.key0_on_dly_tim2;
+		key1_on_dly_tim2 = hsdet_info_def.key1_on_dly_tim2;
+		key2_on_dly_tim2 = hsdet_info_def.key2_on_dly_tim2;
+		hs_det_dbnc = hsdet_info_def.hs_det_dbnc;
+		dbnc_num_plug = hsdet_info_def.dbnc_num_plug;
+	} else {
+		en_plug_det_db = hsdet_info_suspend.en_plug_det_db;
+		en_mic_det = hsdet_info_suspend.en_mic_det;
+		en_dly_key_off = hsdet_info_suspend.en_dly_key_off;
+		en_dly_key_on = hsdet_info_suspend.en_dly_key_on;
+		en_key_off = hsdet_info_suspend.en_key_off;
+		en_key_on = hsdet_info_suspend.en_key_on;
+		key0_on_dly_tim = hsdet_info_suspend.key0_on_dly_tim;
+		key1_on_dly_tim = hsdet_info_suspend.key1_on_dly_tim;
+		key2_on_dly_tim = hsdet_info_suspend.key2_on_dly_tim;
+		key0_on_dly_tim2 = hsdet_info_suspend.key0_on_dly_tim2;
+		key1_on_dly_tim2 = hsdet_info_suspend.key1_on_dly_tim2;
+		key2_on_dly_tim2 = hsdet_info_suspend.key2_on_dly_tim2;
+		hs_det_dbnc = hsdet_info_suspend.hs_det_dbnc;
+		dbnc_num_plug = hsdet_info_suspend.dbnc_num_plug;
+	}
+
+	mc_control(MCDRV_GET_HSDET, (unsigned long)&info, 0);
+	current_en_plug_det_db = info.en_plug_det_db;
+
+	if (flags & MCDRV_HSDET_EVT_SENSEFIN_FLAG)
+		mc_asoc_hpimpclass = res->hp_imp_class;
+
+	if (flags & MCDRV_HSDET_EVT_PLUGUNDET_DB_FLAG) {
+		if (current_en_plug_det_db & MCDRV_PLUGDETDB_UNDET_ENABLE) {
+			mc_asoc_jack_status = 0;
+			snd_soc_jack_report(&hs_jack, 0, SND_JACK_HEADSET);
+			cancel_delayed_work(&delayed_work);
+			info.en_plug_det_db =
+			    en_plug_det_db & MCDRV_PLUGDETDB_DET_ENABLE;
+			info.en_dly_key_off = MCDRV_KEYEN_D_D_D;
+			info.en_dly_key_on = MCDRV_KEYEN_D_D_D;
+			info.en_key_off = MCDRV_KEYEN_D_D_D;
+			info.en_key_on = MCDRV_KEYEN_D_D_D;
+
+			info.hs_det_dbnc = hs_det_dbnc;
+			info.dbnc_num_plug = dbnc_num_plug;
+			info.cbfunc = NULL;
+			err = mc_control(MCDRV_SET_HSDET,
+					 (unsigned long)&info, 0x410000ee);
+
+			info.cbfunc = headset_detect_callback;
+			err = mc_control(MCDRV_SET_HSDET,
+					 (unsigned long)&info, 0x40000000);
+			mc_asoc_hpimpclass = (u8) -1;
+		} else
+			connect_path(mc_asoc_codec);
+	}
+
+	if (mc_asoc_jack_status == SND_JACK_HEADSET) {
+		if ((flags & MCDRV_HSDET_EVT_KEYON0_FLAG) &&
+		    (en_key_on & MCDRV_KEYEN_D_D_E))
+			snd_soc_jack_report(&hs_jack, SND_JACK_BTN_0,
+					    SND_JACK_BTN_0);
+		if ((flags & MCDRV_HSDET_EVT_KEYON1_FLAG)
+		    && (en_key_on & MCDRV_KEYEN_D_E_D))
+			snd_soc_jack_report(&hs_jack, SND_JACK_BTN_1,
+					    SND_JACK_BTN_1);
+		if ((flags & MCDRV_HSDET_EVT_KEYON2_FLAG)
+		    && (en_key_on & MCDRV_KEYEN_E_D_D))
+			snd_soc_jack_report(&hs_jack, SND_JACK_BTN_2,
+					    SND_JACK_BTN_2);
+
+		if (flags & MCDRV_HSDET_EVT_KEYOFF0_FLAG) {
+			if (en_key_off & MCDRV_KEYEN_D_D_E)
+				snd_soc_jack_report(&hs_jack, 0,
+						    SND_JACK_BTN_0);
+			if ((en_dly_key_on & MCDRV_KEYEN_D_D_E)
+			    && !mc_asoc_ver_id
+			    && key0_on_dly_tim2 == 0 && (info.en_key_off & 1)) {
+				info.en_key_off &= ~1;
+				info.key0_on_dly_tim = key0_on_dly_tim;
+				err = mc_control(MCDRV_SET_HSDET,
+						 (unsigned long)&info, 0x2020);
+			}
+		}
+		if (flags & MCDRV_HSDET_EVT_KEYOFF1_FLAG) {
+			if (en_key_off & MCDRV_KEYEN_D_E_D)
+				snd_soc_jack_report(&hs_jack, 0,
+						    SND_JACK_BTN_1);
+			if ((en_dly_key_on & MCDRV_KEYEN_D_E_D)
+			    && !mc_asoc_ver_id
+			    && key1_on_dly_tim2 == 0 && (info.en_key_off & 2)) {
+				info.en_key_off &= ~2;
+				info.key1_on_dly_tim = key1_on_dly_tim;
+				err = mc_control(MCDRV_SET_HSDET,
+						 (unsigned long)&info, 0x4020);
+			}
+		}
+		if (flags & MCDRV_HSDET_EVT_KEYOFF2_FLAG) {
+			if (en_key_off & MCDRV_KEYEN_E_D_D)
+				snd_soc_jack_report(&hs_jack, 0,
+						    SND_JACK_BTN_2);
+			if ((en_dly_key_on & MCDRV_KEYEN_E_D_D)
+			    && !mc_asoc_ver_id
+			    && key2_on_dly_tim2 == 0 && (info.en_key_off & 4)) {
+				info.en_key_off &= ~4;
+				info.key2_on_dly_tim = key2_on_dly_tim;
+				err = mc_control(MCDRV_SET_HSDET,
+						 (unsigned long)&info, 0x8020);
+			}
+		}
+
+		if (flags & MCDRV_HSDET_EVT_DLYKEYON0_FLAG) {
+			if (en_dly_key_on & MCDRV_KEYEN_D_D_E) {
+				input_report_key(inp_dev,
+						 MC_ASOC_EV_KEY_DELAYKEYON0, 1);
+				input_sync(inp_dev);
+				input_report_key(inp_dev,
+						 MC_ASOC_EV_KEY_DELAYKEYON0, 0);
+				input_sync(inp_dev);
+				if (!mc_asoc_ver_id && key0_on_dly_tim2 == 0) {
+					info.en_key_off |= 1;
+					info.key0_on_dly_tim = 0;
+					err = mc_control(MCDRV_SET_HSDET,
+							 (unsigned long)&info,
+							 0x2020);
+				}
+			}
+		} else if (flags & MCDRV_HSDET_EVT_DLYKEYON1_FLAG) {
+			if (en_dly_key_on & MCDRV_KEYEN_D_E_D) {
+				input_report_key(inp_dev,
+						 MC_ASOC_EV_KEY_DELAYKEYON1, 1);
+				input_sync(inp_dev);
+				input_report_key(inp_dev,
+						 MC_ASOC_EV_KEY_DELAYKEYON1, 0);
+				input_sync(inp_dev);
+
+				if (!mc_asoc_ver_id && key1_on_dly_tim2 == 0) {
+					info.en_key_off |= 2;
+					info.key1_on_dly_tim = 0;
+					err = mc_control(MCDRV_SET_HSDET,
+							 (unsigned long)&info,
+							 0x4020);
+				}
+			}
+		} else if (flags & MCDRV_HSDET_EVT_DLYKEYON2_FLAG) {
+			if (en_dly_key_on & MCDRV_KEYEN_E_D_D) {
+				input_report_key(inp_dev,
+						 MC_ASOC_EV_KEY_DELAYKEYON2, 1);
+				input_sync(inp_dev);
+				input_report_key(inp_dev,
+						 MC_ASOC_EV_KEY_DELAYKEYON2, 0);
+				input_sync(inp_dev);
+
+				if (!mc_asoc_ver_id && key2_on_dly_tim2 == 0) {
+					info.en_key_off |= 4;
+					info.key2_on_dly_tim = 0;
+					err = mc_control(MCDRV_SET_HSDET,
+							 (unsigned long)&info,
+							 0x8020);
+				}
+			}
+		}
+
+		if (flags & MCDRV_HSDET_EVT_DLYKEYOFF0_FLAG) {
+			if (en_dly_key_off & MCDRV_KEYEN_D_D_E) {
+				input_report_key(inp_dev,
+						 delay_key_off0[res->key_cnt0],
+						 1);
+				input_sync(inp_dev);
+				input_report_key(inp_dev,
+						 delay_key_off0[res->key_cnt0],
+						 0);
+				input_sync(inp_dev);
+			}
+		} else if (flags & MCDRV_HSDET_EVT_DLYKEYOFF1_FLAG) {
+			if (en_dly_key_off & MCDRV_KEYEN_D_E_D) {
+				input_report_key(inp_dev,
+						 delay_key_off1[res->key_cnt1],
+						 1);
+				input_sync(inp_dev);
+				input_report_key(inp_dev,
+						 delay_key_off1[res->key_cnt1],
+						 0);
+				input_sync(inp_dev);
+			}
+		} else if (flags & MCDRV_HSDET_EVT_DLYKEYOFF2_FLAG) {
+			if (en_dly_key_off & MCDRV_KEYEN_E_D_D) {
+				input_report_key(inp_dev,
+						 delay_key_off2[res->key_cnt2],
+						 1);
+				input_sync(inp_dev);
+				input_report_key(inp_dev,
+						 delay_key_off2[res->key_cnt2],
+						 0);
+				input_sync(inp_dev);
+			}
+		}
+	}
+
+	if ((flags & MCDRV_HSDET_EVT_PLUGDET_DB_FLAG)
+	    && (current_en_plug_det_db & MCDRV_PLUGDETDB_DET_ENABLE)) {
+		if ((flags & MCDRV_HSDET_EVT_MICDET_FLAG)
+		    && (en_mic_det & MCDRV_MICDET_ENABLE)) {
+			mc_asoc_jack_status = SND_JACK_HEADSET;
+			snd_soc_jack_report(&hs_jack,
+					    mc_asoc_jack_status,
+					    SND_JACK_HEADSET);
+		} else {
+			mc_asoc_jack_status = SND_JACK_HEADPHONE;
+			snd_soc_jack_report(&hs_jack,
+					    mc_asoc_jack_status,
+					    SND_JACK_HEADSET);
+		}
+
+		queue_delayed_work(mb4_workq, &delayed_work,
+				   msecs_to_jiffies(MSDETMB4OFF));
+		info.en_plug_det_db =
+		    en_plug_det_db & MCDRV_PLUGDETDB_UNDET_ENABLE;
+		info.en_dly_key_off = en_dly_key_off;
+		info.en_dly_key_on = en_dly_key_on;
+		info.en_key_off = en_key_off;
+		info.en_key_on = en_key_on;
+		info.hs_det_dbnc = HSUNDETDBNC;
+		info.dbnc_num_plug = HSUNDETDBNCNUM;
+		info.cbfunc = NULL;
+		err = mc_control(MCDRV_SET_HSDET,
+				 (unsigned long)&info, 0x410000ee);
+		info.cbfunc = headset_detect_callback;
+		err = mc_control(MCDRV_SET_HSDET,
+				 (unsigned long)&info, 0x40000000);
+		if (info.sgnl_num == MCDRV_SGNLNUM_NONE)
+			mc_asoc_hpimpclass = MC_ASOC_IMP_TBL_NUM - 1;
+	}
+
+	if (mc_asoc_jack_status == SND_JACK_HEADPHONE
+	    && (flags & MCDRV_HSDET_EVT_MICDET_FLAG)
+	    && (en_mic_det & MCDRV_MICDET_ENABLE)) {
+		mc_asoc_jack_status = SND_JACK_HEADSET;
+		snd_soc_jack_report(&hs_jack,
+				    mc_asoc_jack_status, SND_JACK_HEADSET);
+	}
+
+	if (hpimpclass != mc_asoc_hpimpclass) {
+		if (mc_asoc_hpimpclass != (u8) -1) {
+			struct mixer_path_ctl_info mixer;
+			int preset_idx = 0;
+
+			err = get_mixer_path_ctl_info(mc_asoc_codec, &mixer);
+			if (err < 0)
+				return;
+			preset_idx = get_path_preset_idx(&mixer);
+			if (preset_idx < 0 || preset_idx > PRESET_PATH_N)
+				return;
+			set_volume(mc_asoc_codec, &mixer, preset_idx);
+		} else
+			connect_path(mc_asoc_codec);
+	}
+}
+
+static void mc_asoc_irq_work(struct work_struct *work)
+{
+	struct mc_asoc_data *mc_asoc =
+	    container_of(work, struct mc_asoc_data, work);
+	struct spi_device *spi_dev = mc_asoc->spi;
+	int err;
+
+	err = mc_do_irq();
+	if (err < 0)
+		dev_err(&spi_dev->dev, "IRQ processing error: %d\n", err);
+
+	if (IRQ_TYPE == IRQ_TYPE_LEVEL_LOW)
+		enable_irq(mc_asoc->irq);
+}
+
+static irqreturn_t irq_handler(int irq, void *data)
+{
+	struct mc_asoc_data *mc_asoc;
+
+	mc_asoc = (struct mc_asoc_data *)data;
+	if (mc_asoc && mc_asoc->workqueue) {
+		if (IRQ_TYPE == IRQ_TYPE_LEVEL_LOW)
+			disable_irq_nosync(mc_asoc->irq);
+
+		queue_work(mc_asoc->workqueue, &mc_asoc->work);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int init_irq(struct snd_soc_codec *codec)
+{
+	struct mc_asoc_data *mc_asoc;
+	int err;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	INIT_WORK(&mc_asoc->work, mc_asoc_irq_work);
+
+	mc_asoc->workqueue = create_workqueue("irq_queue");
+	if (!mc_asoc->workqueue)
+		return -ENOMEM;
+
+	err = irq_set_irq_type(mc_asoc->irq, IRQ_TYPE);
+	if (err < 0) {
+		dev_err(codec->dev, "Failed to set_irq_type: %d\n", err);
+		return -EIO;
+	}
+
+	err = request_irq(mc_asoc->irq, irq_handler,
+			  IRQF_DISABLED, "MC_YAMAHA IRQ", mc_asoc);
+	if (err < 0)
+		dev_err(codec->dev, "Failed to request_irq: %d\n", err);
+
+	return err;
+}
+
+static int term_irq(struct snd_soc_codec *codec)
+{
+	struct mc_asoc_data *mc_asoc;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (mc_asoc) {
+		free_irq(mc_asoc->irq, mc_asoc);
+
+		if (mc_asoc->workqueue)
+			destroy_workqueue(mc_asoc->workqueue);
+		if (mb4_workq)
+			destroy_workqueue(mb4_workq);
+	}
+
+	return 0;
+}
+
+static int mc_asoc_probe(struct snd_soc_codec *codec)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct device *dev;
+	struct mcdrv_dio_info dio;
+	struct mcdrv_dio_path_info dio_path;
+	u32 update = 0;
+	int i, err;
+
+	mc_asoc_codec = codec;
+	mc_asoc_suspended = false;
+	mc_asoc_hpimpclass = (u8) -1;
+	mc_asoc_jack_status = 0;
+
+	mb4_workq = create_workqueue("mb4");
+	if (!mb4_workq)
+		return -ENOMEM;
+
+	INIT_DELAYED_WORK(&delayed_work, mb4_work);
+
+	if (!codec)
+		return -ENODEV;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	dev = codec->dev;
+	if (!mc_asoc || !dev)
+		return -ENODEV;
+
+	mc_asoc_ver_id = mc_version_id_get();
+
+	mc_asoc->setup = mc_asoc_cfg_setup;
+	if (mc_asoc_ver_id < 2) {
+		mc_asoc->setup.info.mb_sel1 = MCDRV_MBSEL_20;
+		mc_asoc->setup.info.mb_sel2 = MCDRV_MBSEL_20;
+		mc_asoc->setup.info.mb_sel3 = MCDRV_MBSEL_20;
+		mc_asoc->setup.info.mb_sel4 = MCDRV_MBSEL_20;
+	}
+
+	err = mc_init(&mc_asoc->setup.info);
+	if (err < 0) {
+		dev_err(dev, "Error in mc_init: %d\n", err);
+		return err;
+	}
+
+	if (mc_asoc_ver_id == 0) {
+		vreg_map[MC_ASOC_AVOL_HP].volmap = volmap_hp_es1;
+		vreg_map[MC_ASOC_AVOL_LINEOUT2].volmap = volmap_lineout;
+		vreg_map[MC_ASOC_DVOL_ADIF0IN].volmap = volmap_adif;
+		vreg_map[MC_ASOC_DVOL_ADIF1IN].volmap = volmap_adif;
+		vreg_map[MC_ASOC_DVOL_APLAY_D].volmap = volmap_adif;
+	} else
+		vreg_map[MC_ASOC_AVOL_SP].volmap = volmap_sp[4];
+
+	err = snd_soc_add_codec_controls(codec, mc_asoc_snd_controls,
+					 ARRAY_SIZE(mc_asoc_snd_controls));
+	if (err < 0) {
+		dev_err(dev, "Error in snd_soc_add_codec_controls: %d\n", err);
+		goto error;
+	}
+
+	err = mc_asoc_add_widgets(codec);
+	if (err < 0) {
+		dev_err(dev, "Error in mc_asoc_add_widgets: %d\n", err);
+		goto error;
+	}
+
+	snd_soc_cache_write(codec, MC_ASOC_EXT_MASTERSLAVE,
+			    ext_port_def.dio_common.master_slave);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_RATE,
+			    ext_port_def.dio_common.fs);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_BITCLOCK_RATE,
+			    ext_port_def.dio_common.bck_fs);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INTERFACE,
+			    ext_port_def.dio_common.interface);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_BITCLOCK_INVERT,
+			    ext_port_def.dio_common.bck_invert);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INPUT_DA_BIT_WIDTH,
+			    ext_port_def.dir.da_format.bit_sel);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_OUTPUT_DA_BIT_WIDTH,
+			    ext_port_def.dit.da_format.bit_sel);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INPUT_DA_FORMAT,
+			    ext_port_def.dir.da_format.mode);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_OUTPUT_DA_FORMAT,
+			    ext_port_def.dit.da_format.mode);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INPUT_PCM_MONOSTEREO,
+			    ext_port_def.dir.pcm_format.mono);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_OUTPUT_PCM_MONOSTEREO,
+			    ext_port_def.dit.pcm_format.mono);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INPUT_PCM_BIT_ORDER,
+			    ext_port_def.dir.pcm_format.order);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_OUTPUT_PCM_BIT_ORDER,
+			    ext_port_def.dit.pcm_format.order);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INPUT_PCM_FORMAT,
+			    ext_port_def.dir.pcm_format.law);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_OUTPUT_PCM_FORMAT,
+			    ext_port_def.dit.pcm_format.law);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_INPUT_PCM_BIT_WIDTH,
+			    ext_port_def.dir.pcm_format.bit_sel);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_OUTPUT_PCM_BIT_WIDTH,
+			    ext_port_def.dit.pcm_format.bit_sel);
+
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_MASTERSLAVE,
+			    voice_port_def.dio_common.master_slave);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_RATE,
+			    voice_port_def.dio_common.fs);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_BITCLOCK_RATE,
+			    voice_port_def.dio_common.bck_fs);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INTERFACE,
+			    voice_port_def.dio_common.interface);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_BITCLOCK_INVERT,
+			    voice_port_def.dio_common.bck_invert);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INPUT_DA_BIT_WIDTH,
+			    voice_port_def.dir.da_format.bit_sel);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_OUTPUT_DA_BIT_WIDTH,
+			    voice_port_def.dit.da_format.bit_sel);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INPUT_DA_FORMAT,
+			    voice_port_def.dir.da_format.mode);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_OUTPUT_DA_FORMAT,
+			    voice_port_def.dit.da_format.mode);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INPUT_PCM_MONOSTEREO,
+			    voice_port_def.dir.pcm_format.mono);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_OUTPUT_PCM_MONOSTEREO,
+			    voice_port_def.dit.pcm_format.mono);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INPUT_PCM_BIT_ORDER,
+			    voice_port_def.dir.pcm_format.order);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_OUTPUT_PCM_BIT_ORDER,
+			    voice_port_def.dit.pcm_format.order);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INPUT_PCM_FORMAT,
+			    voice_port_def.dir.pcm_format.law);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_OUTPUT_PCM_FORMAT,
+			    voice_port_def.dit.pcm_format.law);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_INPUT_PCM_BIT_WIDTH,
+			    voice_port_def.dir.pcm_format.bit_sel);
+
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_OUTPUT_PCM_BIT_WIDTH,
+			    voice_port_def.dit.pcm_format.bit_sel);
+
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_RECORDING,
+			    VOICE_RECORDING_UNMUTE);
+	snd_soc_cache_write(codec, MC_ASOC_INCALL_MIC_SP, INCALL_MIC_SP);
+	snd_soc_cache_write(codec, MC_ASOC_INCALL_MIC_RC, INCALL_MIC_RC);
+	snd_soc_cache_write(codec, MC_ASOC_INCALL_MIC_HP, INCALL_MIC_HP);
+	snd_soc_cache_write(codec, MC_ASOC_INCALL_MIC_LO1, INCALL_MIC_LO1);
+	snd_soc_cache_write(codec, MC_ASOC_INCALL_MIC_LO2, INCALL_MIC_LO2);
+
+	snd_soc_cache_write(codec, MC_ASOC_MUSIC_PHYSICAL_PORT,
+			    MUSIC_PHYSICAL_PORT);
+	snd_soc_cache_write(codec, MC_ASOC_EXT_PHYSICAL_PORT,
+			    EXT_PHYSICAL_PORT);
+	snd_soc_cache_write(codec, MC_ASOC_VOICE_PHYSICAL_PORT,
+			    VOICE_PHYSICAL_PORT);
+	snd_soc_cache_write(codec, MC_ASOC_HIFI_PHYSICAL_PORT,
+			    HIFI_PHYSICAL_PORT);
+
+	snd_soc_cache_write(codec, MC_ASOC_MAIN_MIC, mc_asoc_main_mic);
+	snd_soc_cache_write(codec, MC_ASOC_SUB_MIC, mc_asoc_sub_mic);
+	snd_soc_cache_write(codec, MC_ASOC_HS_MIC, mc_asoc_hs_mic);
+#ifdef MC_ASOC_TEST
+	snd_soc_cache_write(codec, MC_ASOC_MIC1_BIAS, mc_asoc_mic1_bias);
+	snd_soc_cache_write(codec, MC_ASOC_MIC2_BIAS, mc_asoc_mic2_bias);
+	snd_soc_cache_write(codec, MC_ASOC_MIC3_BIAS, mc_asoc_mic3_bias);
+	snd_soc_cache_write(codec, MC_ASOC_MIC4_BIAS, mc_asoc_mic4_bias);
+#endif
+
+	/* Headset jack detection */
+	snd_soc_jack_new(codec, "Headset",
+			 SND_JACK_HEADSET | SND_JACK_BTN_0 |
+			 SND_JACK_BTN_1 | SND_JACK_BTN_2, &hs_jack);
+
+	snd_jack_set_key(hs_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
+	snd_jack_set_key(hs_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+	snd_jack_set_key(hs_jack.jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+
+	snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), hs_jack_pins);
+
+	inp_dev = input_allocate_device();
+	inp_dev->name = "Headset keys";
+	input_set_capability(inp_dev, EV_KEY, MC_ASOC_EV_KEY_DELAYKEYON0);
+	input_set_capability(inp_dev, EV_KEY, MC_ASOC_EV_KEY_DELAYKEYON1);
+	input_set_capability(inp_dev, EV_KEY, MC_ASOC_EV_KEY_DELAYKEYON2);
+	for (i = 0; i < 8; i++) {
+		input_set_capability(inp_dev, EV_KEY, delay_key_off0[i]);
+		input_set_capability(inp_dev, EV_KEY, delay_key_off1[i]);
+		input_set_capability(inp_dev, EV_KEY, delay_key_off2[i]);
+	}
+
+	err = input_register_device(inp_dev);
+	if (err < 0) {
+		dev_err(dev, "Error in input_register_device: %d\n", err);
+		goto error;
+	}
+
+	dio.port[0] = music_port_def;
+	dio.port[1] = ext_port_def;
+	dio.port[2] = voice_port_def;
+	dio.port[3] = hifi_port_def;
+
+	update = MCDRV_MUSIC_COM_UPDATE_FLAG
+	    | MCDRV_MUSIC_DIR_UPDATE_FLAG
+	    | MCDRV_MUSIC_DIT_UPDATE_FLAG
+	    | MCDRV_EXT_COM_UPDATE_FLAG
+	    | MCDRV_EXT_DIR_UPDATE_FLAG
+	    | MCDRV_EXT_DIT_UPDATE_FLAG
+	    | MCDRV_VOICE_COM_UPDATE_FLAG
+	    | MCDRV_VOICE_DIR_UPDATE_FLAG
+	    | MCDRV_VOICE_DIT_UPDATE_FLAG
+	    | MCDRV_HIFI_COM_UPDATE_FLAG
+	    | MCDRV_HIFI_DIR_UPDATE_FLAG | MCDRV_HIFI_DIT_UPDATE_FLAG;
+	err = mc_control(MCDRV_SET_DIGITALIO, (unsigned long)&dio, update);
+	if (err < 0) {
+		dev_err(dev, "Error in MCDRV_SET_DIGITALIO: %d\n", err);
+		goto error;
+	}
+
+	update = MCDRV_PHYS0_UPDATE_FLAG
+	    | MCDRV_PHYS1_UPDATE_FLAG
+	    | MCDRV_PHYS2_UPDATE_FLAG
+	    | MCDRV_PHYS3_UPDATE_FLAG
+	    | MCDRV_DIR0SLOT_UPDATE_FLAG
+	    | MCDRV_DIR1SLOT_UPDATE_FLAG
+	    | MCDRV_DIR2SLOT_UPDATE_FLAG
+	    | MCDRV_DIT0SLOT_UPDATE_FLAG
+	    | MCDRV_DIT1SLOT_UPDATE_FLAG | MCDRV_DIT2SLOT_UPDATE_FLAG;
+	dio_path.phys_port[0] = MUSIC_PHYSICAL_PORT;
+	dio_path.phys_port[1] = EXT_PHYSICAL_PORT;
+	dio_path.phys_port[2] = VOICE_PHYSICAL_PORT;
+	dio_path.phys_port[3] = HIFI_PHYSICAL_PORT;
+	dio_path.music_rslot[0] = mc_asoc_cfg_setup.rslot[0];
+	dio_path.music_rslot[1] = mc_asoc_cfg_setup.rslot[1];
+	dio_path.music_rslot[2] = mc_asoc_cfg_setup.rslot[2];
+	dio_path.music_tslot[0] = mc_asoc_cfg_setup.tslot[0];
+	dio_path.music_tslot[1] = mc_asoc_cfg_setup.tslot[1];
+	dio_path.music_tslot[2] = mc_asoc_cfg_setup.tslot[2];
+	err = mc_control(MCDRV_SET_DIGITALIO_PATH,
+			 (unsigned long)&dio_path, update);
+	if (err < 0) {
+		dev_err(dev, "Error in MCDRV_SET_DIGITALIO_PATH: %d\n", err);
+		goto error;
+	}
+
+	mc_asoc->hsdet_store = hsdet_info_def;
+	mc_asoc->hsdet_store.en_dly_key_off = MCDRV_KEYEN_D_D_D;
+	mc_asoc->hsdet_store.en_dly_key_on = MCDRV_KEYEN_D_D_D;
+	mc_asoc->hsdet_store.en_key_off = MCDRV_KEYEN_D_D_D;
+	mc_asoc->hsdet_store.en_key_on = MCDRV_KEYEN_D_D_D;
+	mc_asoc->hsdet_store.cbfunc = headset_detect_callback;
+	if (mc_asoc_ver_id == 0)
+		mc_asoc->hsdet_store.irq_type = MCDRV_IRQTYPE_NORMAL;
+
+	err = mc_control(MCDRV_SET_HSDET,
+			 (unsigned long)&mc_asoc->hsdet_store, 0x7fffffff);
+	if (err < 0) {
+		dev_err(dev, "Error in MCDRV_SET_HSDET: %d\n", err);
+		goto error;
+	}
+
+	err = connect_path(codec);
+	if (err < 0) {
+		dev_err(dev, "Error in coeenct_path: %d\n", err);
+		goto error;
+	}
+
+	err = mc_do_irq();
+	if (err < 0)
+		dev_err(dev, "Error in mc_do_IRQ: %d\n", err);
+
+	if (mc_asoc_ver_id) {
+		mc_asoc->hsdet_store.en_plug_det_db &=
+		    ~MCDRV_PLUGDETDB_UNDET_ENABLE;
+		err = mc_control(MCDRV_SET_HSDET,
+				 (unsigned long)&mc_asoc->hsdet_store, 0x2);
+		if (err < 0) {
+			dev_err(dev, "Error in MCDRV_SET_HSDET: %d\n", err);
+			goto error;
+		}
+	}
+
+	err = init_irq(codec);
+	if (err < 0) {
+		dev_err(dev, "Error in init_irq: %d\n", err);
+		goto error;
+	}
+
+	device_init_wakeup(dev, 1);
+
+	set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	return 0;
+
+error:
+	mc_term();
+
+	return err;
+}
+
+static int mc_asoc_remove(struct snd_soc_codec *codec)
+{
+	struct mc_asoc_data *mc_asoc;
+	int err;
+
+	if (!codec)
+		return -EINVAL;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	term_irq(codec);
+
+	input_unregister_device(inp_dev);
+
+	del_dsp_param(mc_asoc);
+
+	set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	err = mc_term();
+	if (err < 0)
+		dev_err(codec->dev, "Error in mc_term: %d\n", err);
+
+	return err;
+}
+
+static int mc_asoc_suspend(struct snd_soc_codec *codec)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mixer_path_ctl_info mixer;
+	struct mcdrv_hsdet_info hsdet_info;
+	int err;
+
+	if (!codec)
+		return -EINVAL;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	get_mixer_path_ctl_info(codec, &mixer);
+	if (mixer.audio_mode_play || mixer.audio_mode_cap
+	    || mixer.mainmic_play || mixer.submic_play || mixer.msmic_play
+	    || mixer.hsmic_play || mixer.btmic_play || mixer.lin1_play
+	    || mixer.dtmf_control)
+		return 0;
+
+	set_bias_level(codec, SND_SOC_BIAS_OFF);
+
+	mutex_lock(&mc_asoc->mutex);
+
+	err = mc_control(MCDRV_GET_HSDET,
+			 (unsigned long)&mc_asoc->hsdet_store, 0);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in mc_asoc_suspend: %d\n", err);
+		goto error;
+	}
+
+	mc_asoc->hsdet_store.dly_irq_stop = hsdet_info_def.dly_irq_stop;
+
+	if (device_may_wakeup(codec->dev))
+		enable_irq_wake(mc_asoc->irq);
+
+	hsdet_info = hsdet_info_suspend;
+	if (!mc_asoc_ver_id)
+		hsdet_info.irq_type = MCDRV_IRQTYPE_NORMAL;
+
+	if (mc_asoc_jack_status != SND_JACK_HEADSET) {
+		hsdet_info.en_dly_key_off = MCDRV_KEYEN_D_D_D;
+		hsdet_info.en_dly_key_on = MCDRV_KEYEN_D_D_D;
+		hsdet_info.en_key_off = MCDRV_KEYEN_D_D_D;
+		hsdet_info.en_key_on = MCDRV_KEYEN_D_D_D;
+	}
+
+	hsdet_info.en_plug_det_db &= mc_asoc->hsdet_store.en_plug_det_db;
+	err = mc_control(MCDRV_SET_HSDET,
+			 (unsigned long)&hsdet_info, 0x7fffffff);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in mc_asoc_suspend: %d\n", err);
+		goto error;
+	}
+
+	hsdet_info.cbfunc = headset_detect_callback;
+	err = mc_control(MCDRV_SET_HSDET,
+			 (unsigned long)&hsdet_info, 0x40000000);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in mc_asoc_suspend: %d\n", err);
+		goto error;
+	}
+
+	mc_asoc_suspended = true;
+error:
+	mutex_unlock(&mc_asoc->mutex);
+
+	return err;
+}
+
+static int mc_asoc_resume(struct snd_soc_codec *codec)
+{
+	struct mc_asoc_data *mc_asoc;
+	struct mcdrv_hsdet_info hsdet_info;
+	int err;
+
+	if (!mc_asoc_suspended)
+		return 0;
+
+	mc_asoc = snd_soc_codec_get_drvdata(codec);
+	if (!mc_asoc)
+		return -EINVAL;
+
+	mutex_lock(&mc_asoc->mutex);
+
+	set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+
+	err = mc_control(MCDRV_GET_HSDET, (unsigned long)&hsdet_info, 0);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in mc_asoc_resume: %d\n", err);
+		goto error;
+	}
+
+	mc_asoc->hsdet_store.en_plug_det_db =
+	    hsdet_info_def.en_plug_det_db & hsdet_info.en_plug_det_db;
+	if (mc_asoc_jack_status != SND_JACK_HEADSET) {
+		mc_asoc->hsdet_store.en_dly_key_off = MCDRV_KEYEN_D_D_D;
+		mc_asoc->hsdet_store.en_dly_key_on = MCDRV_KEYEN_D_D_D;
+		mc_asoc->hsdet_store.en_key_off = MCDRV_KEYEN_D_D_D;
+		mc_asoc->hsdet_store.en_key_on = MCDRV_KEYEN_D_D_D;
+	} else {
+		mc_asoc->hsdet_store.en_dly_key_off =
+		    hsdet_info_def.en_dly_key_off;
+		mc_asoc->hsdet_store.en_dly_key_on =
+		    hsdet_info_def.en_dly_key_on;
+		mc_asoc->hsdet_store.en_key_off = hsdet_info_def.en_key_off;
+		mc_asoc->hsdet_store.en_key_on = hsdet_info_def.en_key_on;
+	}
+
+	mc_asoc->hsdet_store.cbfunc = NULL;
+	err = mc_control(MCDRV_SET_HSDET,
+			 (unsigned long)&mc_asoc->hsdet_store, 0x7fffffff);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in mc_asoc_resume: %d\n", err);
+		goto error;
+	}
+
+	mc_asoc->hsdet_store.cbfunc = headset_detect_callback;
+	err = mc_control(MCDRV_SET_HSDET,
+			 (unsigned long)&mc_asoc->hsdet_store, 0x40000000);
+	if (err < 0) {
+		dev_err(codec->dev, "Error in mc_asoc_resume: %d\n", err);
+		goto error;
+	}
+
+	if (device_may_wakeup(codec->dev))
+		disable_irq_wake(mc_asoc->irq);
+
+	mc_asoc_suspended = false;
+
+error:
+	mutex_unlock(&mc_asoc->mutex);
+
+	return err;
+}
+
+static struct snd_soc_codec_driver mc_asoc_codec_dev = {
+	.probe = mc_asoc_probe,
+	.remove = mc_asoc_remove,
+	.suspend = mc_asoc_suspend,
+	.resume = mc_asoc_resume,
+	.read = mc_asoc_read_reg,
+	.write = mc_asoc_write_reg,
+	.reg_cache_size = MC_ASOC_N_REG,
+	.reg_word_size = sizeof(u16),
+	.reg_cache_step = 1,
+	.idle_bias_off = true,
+	.set_bias_level = set_bias_level
+};
+
+static int spi_rw(struct spi_device *spi_dev, u8 *tx, u8 *rx, int len)
+{
+	struct spi_message spi_msg;
+	struct spi_transfer spi_xfer;
+
+	spi_message_init(&spi_msg);
+
+	memset(&spi_xfer, 0, sizeof(spi_xfer));
+	spi_xfer.len = len;
+	spi_xfer.tx_buf = tx;
+	spi_xfer.rx_buf = rx;
+
+	spi_message_add_tail(&spi_xfer, &spi_msg);
+
+	if (spi_sync(spi_dev, &spi_msg)) {
+		dev_err(&spi_dev->dev, "spi_sync failure\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static u8 spi_buf[1024];
+
+static int mc_asoc_read_data(void *bus_priv, enum mcdrv_slave_addr slave_addr,
+			     u8 addr, u8 *data, u32 size)
+{
+	struct spi_device *spi_dev = (struct spi_device *)bus_priv;
+	u8 tx[2];
+	u8 *rx = NULL;
+	u8 *readbuf = spi_buf;
+	int err;
+
+	if (size + 1 > sizeof(spi_buf)) {
+		rx = kzalloc(size + 1, GFP_KERNEL);
+		if (!rx) {
+			dev_err(&spi_dev->dev, "Failed to allocate memory\n");
+			return -ENOMEM;
+		}
+
+		readbuf = rx;
+	}
+
+	tx[0] = (addr << 1) | 0x80;
+	tx[1] = 0;
+	if (size > 1)
+		tx[0] |= 0x01;	/* burst */
+
+	err = spi_rw(spi_dev, tx, readbuf, size + 1);
+	if (!err)
+		memcpy(data, readbuf + 1, size);
+
+	kfree(rx);
+
+	return err;
+}
+
+static int mc_asoc_write_data(void *bus_priv, enum mcdrv_slave_addr slave_addr,
+			      u8 *data, u32 size)
+{
+	struct spi_device *spi_dev = (struct spi_device *)bus_priv;
+
+	return spi_rw(spi_dev, data, NULL, size);
+}
+
+static struct mcdrv_bus_ops mc_asoc_bus_ops = {
+	.read = mc_asoc_read_data,
+	.write = mc_asoc_write_data,
+};
+
+static int __devinit mc_asoc_spi_probe(struct spi_device *spi)
+{
+	struct mc_asoc_data *mc_asoc;
+	int err;
+
+	mc_asoc = kzalloc(sizeof(struct mc_asoc_data), GFP_KERNEL);
+	if (!mc_asoc) {
+		dev_err(&spi->dev, "Failed to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	mc_asoc->spi = spi;
+	mc_asoc->irq = spi->irq;
+	pr_info("MC ASOC IRQ1: %d\n", spi->irq);
+	mutex_init(&mc_asoc->mutex);
+	dev_set_drvdata(&spi->dev, mc_asoc);
+
+	err = snd_soc_register_codec(&spi->dev, &mc_asoc_codec_dev,
+				     mc_asoc_dai, ARRAY_SIZE(mc_asoc_dai));
+	if (err < 0) {
+		dev_set_drvdata(&spi->dev, NULL);
+		mutex_destroy(&mc_asoc->mutex);
+		kfree(mc_asoc);
+		dev_err(&spi->dev, "Failed to register codec: error=%d\n", err);
+		return err;
+	}
+
+	mc_asoc_bus_ops.priv = spi;
+	mc_bus_register(&mc_asoc_bus_ops);
+
+	return 0;
+}
+
+static int __devexit mc_asoc_spi_remove(struct spi_device *spi)
+{
+	struct mc_asoc_data *mc_asoc = dev_get_drvdata(&spi->dev);
+
+	if (mc_asoc) {
+		dev_set_drvdata(&spi->dev, NULL);
+		mutex_destroy(&mc_asoc->mutex);
+		kfree(mc_asoc);
+	}
+
+	mc_bus_register(NULL);
+	snd_soc_unregister_codec(&spi->dev);
+
+	return 0;
+}
+
+static struct spi_driver mc_asoc_spi_driver = {
+	.driver = {
+		   .name = MC_ASOC_NAME,
+		   .owner = THIS_MODULE,
+		   },
+	.probe = mc_asoc_spi_probe,
+	.remove = __devexit_p(mc_asoc_spi_remove),
+};
+
+static int __init ymu831_init(void)
+{
+	int err;
+
+	err = spi_register_driver(&mc_asoc_spi_driver);
+	if (err)
+		pr_err("Failed to register YMU831 SPI driver: %d\n", err);
+
+	return err;
+}
+
+module_init(ymu831_init);
+
+static void __exit ymu831_exit(void)
+{
+	spi_unregister_driver(&mc_asoc_spi_driver);
+}
+
+module_exit(ymu831_exit);
+
+MODULE_AUTHOR("Yamaha Corporation");
+MODULE_DESCRIPTION("Yamaha YMU831 ALSA SoC codec driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MC_ASOC_DRIVER_VERSION);
diff --git a/sound/soc/codecs/ymu831/ymu831.h b/sound/soc/codecs/ymu831/ymu831.h
new file mode 100644
index 0000000..a38b976
--- /dev/null
+++ b/sound/soc/codecs/ymu831/ymu831.h
@@ -0,0 +1,48 @@
+/*
+ * YMU831 ASoC codec driver
+ *
+ * Copyright (c) 2012 Yamaha Corporation
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*
+ * changelog:
+ * - change in the Linux coding style
+ * - remove unnecessary comments
+ * - remove unused codes
+ */
+#ifndef _YMU831_H
+#define _YMU831_H
+
+#define MC_ASOC_NAME			"ymu831"
+
+/* div id */
+#define MC_ASOC_BCLK_MULT		5
+
+/* div for MC_ASOC_BCLK_MULT */
+#define MC_ASOC_LRCK_X64		0
+#define MC_ASOC_LRCK_X48		1
+#define MC_ASOC_LRCK_X32		2
+#define MC_ASOC_LRCK_X512		3
+#define MC_ASOC_LRCK_X256		4
+#define MC_ASOC_LRCK_X192		5
+#define MC_ASOC_LRCK_X128		6
+#define MC_ASOC_LRCK_X96		7
+#define MC_ASOC_LRCK_X24		8
+#define MC_ASOC_LRCK_X16		9
+
+#endif /* _YMU831_H */
diff --git a/sound/soc/codecs/ymu831/ymu831_priv.h b/sound/soc/codecs/ymu831/ymu831_priv.h
new file mode 100644
index 0000000..10bce05
--- /dev/null
+++ b/sound/soc/codecs/ymu831/ymu831_priv.h
@@ -0,0 +1,278 @@
+/*
+ * YMU831 ASoC codec driver - private header
+ *
+ * Copyright (c) 2012 Yamaha Corporation
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/*
+ * changelog:
+ * - change in the Linux coding style
+ * - remove unnecessary comments
+ * - remove unused codes
+ */
+#ifndef _YMU831_PRIV_H
+#define _YMU831_PRIV_H
+
+#include <linux/spi/spi.h>
+
+#include "mcdriver.h"
+
+#undef MC_ASOC_TEST
+
+/*
+ * Virtual registers
+ */
+enum {
+	MC_ASOC_DVOL_MUSICIN,
+	MC_ASOC_DVOL_EXTIN,
+	MC_ASOC_DVOL_VOICEIN,
+	MC_ASOC_DVOL_REFIN,
+	MC_ASOC_DVOL_ADIF0IN,
+	MC_ASOC_DVOL_ADIF1IN,
+	MC_ASOC_DVOL_ADIF2IN,
+	MC_ASOC_DVOL_MUSICOUT,
+	MC_ASOC_DVOL_EXTOUT,
+	MC_ASOC_DVOL_VOICEOUT,
+	MC_ASOC_DVOL_REFOUT,
+	MC_ASOC_DVOL_DAC0OUT,
+	MC_ASOC_DVOL_DAC1OUT,
+	MC_ASOC_DVOL_DPATHDA,
+	MC_ASOC_DVOL_DPATHAD,
+	MC_ASOC_AVOL_LINEIN1,
+	MC_ASOC_AVOL_MIC1,
+	MC_ASOC_AVOL_MIC2,
+	MC_ASOC_AVOL_MIC3,
+	MC_ASOC_AVOL_MIC4,
+	MC_ASOC_AVOL_HP,
+	MC_ASOC_AVOL_SP,
+	MC_ASOC_AVOL_RC,
+	MC_ASOC_AVOL_LINEOUT1,
+	MC_ASOC_AVOL_LINEOUT2,
+	MC_ASOC_AVOL_SP_GAIN,
+
+	MC_ASOC_DVOL_MASTER,
+	MC_ASOC_DVOL_VOICE,
+	MC_ASOC_DVOL_APLAY_A,
+	MC_ASOC_DVOL_APLAY_D,
+
+	MC_ASOC_VOICE_RECORDING,
+
+	MC_ASOC_AUDIO_MODE_PLAY,
+	MC_ASOC_AUDIO_MODE_CAP,
+	MC_ASOC_OUTPUT_PATH,
+	MC_ASOC_INPUT_PATH,
+	MC_ASOC_INCALL_MIC_SP,
+	MC_ASOC_INCALL_MIC_RC,
+	MC_ASOC_INCALL_MIC_HP,
+	MC_ASOC_INCALL_MIC_LO1,
+	MC_ASOC_INCALL_MIC_LO2,
+
+	MC_ASOC_MAINMIC_PLAYBACK_PATH,
+	MC_ASOC_SUBMIC_PLAYBACK_PATH,
+	MC_ASOC_2MIC_PLAYBACK_PATH,
+	MC_ASOC_HSMIC_PLAYBACK_PATH,
+	MC_ASOC_BTMIC_PLAYBACK_PATH,
+	MC_ASOC_LIN1_PLAYBACK_PATH,
+
+	MC_ASOC_DTMF_CONTROL,
+	MC_ASOC_DTMF_OUTPUT,
+
+	MC_ASOC_SWITCH_CLOCK,
+
+	MC_ASOC_EXT_MASTERSLAVE,
+	MC_ASOC_EXT_RATE,
+	MC_ASOC_EXT_BITCLOCK_RATE,
+	MC_ASOC_EXT_INTERFACE,
+	MC_ASOC_EXT_BITCLOCK_INVERT,
+	MC_ASOC_EXT_INPUT_DA_BIT_WIDTH,
+	MC_ASOC_EXT_INPUT_DA_FORMAT,
+	MC_ASOC_EXT_INPUT_PCM_MONOSTEREO,
+	MC_ASOC_EXT_INPUT_PCM_BIT_ORDER,
+	MC_ASOC_EXT_INPUT_PCM_FORMAT,
+	MC_ASOC_EXT_INPUT_PCM_BIT_WIDTH,
+	MC_ASOC_EXT_OUTPUT_DA_BIT_WIDTH,
+	MC_ASOC_EXT_OUTPUT_DA_FORMAT,
+	MC_ASOC_EXT_OUTPUT_PCM_MONOSTEREO,
+	MC_ASOC_EXT_OUTPUT_PCM_BIT_ORDER,
+	MC_ASOC_EXT_OUTPUT_PCM_FORMAT,
+	MC_ASOC_EXT_OUTPUT_PCM_BIT_WIDTH,
+
+	MC_ASOC_VOICE_MASTERSLAVE,
+	MC_ASOC_VOICE_RATE,
+	MC_ASOC_VOICE_BITCLOCK_RATE,
+	MC_ASOC_VOICE_INTERFACE,
+	MC_ASOC_VOICE_BITCLOCK_INVERT,
+	MC_ASOC_VOICE_INPUT_DA_BIT_WIDTH,
+	MC_ASOC_VOICE_INPUT_DA_FORMAT,
+	MC_ASOC_VOICE_INPUT_PCM_MONOSTEREO,
+	MC_ASOC_VOICE_INPUT_PCM_BIT_ORDER,
+	MC_ASOC_VOICE_INPUT_PCM_FORMAT,
+	MC_ASOC_VOICE_INPUT_PCM_BIT_WIDTH,
+	MC_ASOC_VOICE_OUTPUT_DA_BIT_WIDTH,
+	MC_ASOC_VOICE_OUTPUT_DA_FORMAT,
+	MC_ASOC_VOICE_OUTPUT_PCM_MONOSTEREO,
+	MC_ASOC_VOICE_OUTPUT_PCM_BIT_ORDER,
+	MC_ASOC_VOICE_OUTPUT_PCM_FORMAT,
+	MC_ASOC_VOICE_OUTPUT_PCM_BIT_WIDTH,
+
+	MC_ASOC_MUSIC_PHYSICAL_PORT,
+	MC_ASOC_EXT_PHYSICAL_PORT,
+	MC_ASOC_VOICE_PHYSICAL_PORT,
+	MC_ASOC_HIFI_PHYSICAL_PORT,
+
+	MC_ASOC_ADIF0_SWAP,
+	MC_ASOC_ADIF1_SWAP,
+	MC_ASOC_ADIF2_SWAP,
+
+	MC_ASOC_DAC0_SWAP,
+	MC_ASOC_DAC1_SWAP,
+
+	MC_ASOC_MUSIC_OUT0_SWAP,
+
+	MC_ASOC_MUSIC_IN0_SWAP,
+	MC_ASOC_MUSIC_IN1_SWAP,
+	MC_ASOC_MUSIC_IN2_SWAP,
+
+	MC_ASOC_EXT_IN_SWAP,
+
+	MC_ASOC_VOICE_IN_SWAP,
+
+	MC_ASOC_MUSIC_OUT1_SWAP,
+	MC_ASOC_MUSIC_OUT2_SWAP,
+
+	MC_ASOC_EXT_OUT_SWAP,
+
+	MC_ASOC_VOICE_OUT_SWAP,
+
+	MC_ASOC_ADIF0_SOURCE,
+	MC_ASOC_ADIF1_SOURCE,
+	MC_ASOC_ADIF2_SOURCE,
+
+	MC_ASOC_PARAMETER_SETTING,
+
+	MC_ASOC_MAIN_MIC,
+	MC_ASOC_SUB_MIC,
+	MC_ASOC_HS_MIC,
+#ifdef MC_ASOC_TEST
+	MC_ASOC_MIC1_BIAS,
+	MC_ASOC_MIC2_BIAS,
+	MC_ASOC_MIC3_BIAS,
+	MC_ASOC_MIC4_BIAS,
+#endif
+
+	MC_ASOC_N_REG
+};
+
+#define MC_ASOC_N_VOL_REG			(MC_ASOC_DVOL_APLAY_D + 1)
+
+#define MC_ASOC_AUDIO_MODE_OFF			0
+#define MC_ASOC_AUDIO_MODE_AUDIO		1
+#define MC_ASOC_AUDIO_MODE_INCALL		2
+#define MC_ASOC_AUDIO_MODE_AUDIO_INCALL		3
+#define MC_ASOC_AUDIO_MODE_INCOMM		4
+#define MC_ASOC_AUDIO_MODE_KARAOKE		5
+#define MC_ASOC_AUDIO_MODE_AUDIOEX		5
+#define MC_ASOC_AUDIO_MODE_AUDIOVR		6
+#define MC_ASOC_AUDIO_MODE_INCALL2		6
+#define MC_ASOC_AUDIO_MODE_AUDIO_INCALL2	7
+#define MC_ASOC_AUDIO_MODE_INCOMM2		8
+
+#define MC_ASOC_OUTPUT_PATH_SP			0
+#define MC_ASOC_OUTPUT_PATH_RC			1
+#define MC_ASOC_OUTPUT_PATH_HP			2
+#define MC_ASOC_OUTPUT_PATH_HS			3
+#define MC_ASOC_OUTPUT_PATH_LO1			4
+#define MC_ASOC_OUTPUT_PATH_LO2			5
+#define MC_ASOC_OUTPUT_PATH_BT			6
+#define MC_ASOC_OUTPUT_PATH_SP_RC		7
+#define MC_ASOC_OUTPUT_PATH_SP_HP		8
+#define MC_ASOC_OUTPUT_PATH_SP_LO1		9
+#define MC_ASOC_OUTPUT_PATH_SP_LO2		10
+#define MC_ASOC_OUTPUT_PATH_SP_BT		11
+#define MC_ASOC_OUTPUT_PATH_LO1_RC		12
+#define MC_ASOC_OUTPUT_PATH_LO1_HP		13
+#define MC_ASOC_OUTPUT_PATH_LO1_BT		14
+#define MC_ASOC_OUTPUT_PATH_LO2_RC		15
+#define MC_ASOC_OUTPUT_PATH_LO2_HP		16
+#define MC_ASOC_OUTPUT_PATH_LO2_BT		17
+#define MC_ASOC_OUTPUT_PATH_LO1_LO2		18
+#define MC_ASOC_OUTPUT_PATH_LO2_LO1		19
+
+#define MC_ASOC_INPUT_PATH_MAINMIC		0
+#define MC_ASOC_INPUT_PATH_SUBMIC		1
+#define MC_ASOC_INPUT_PATH_2MIC			2
+#define MC_ASOC_INPUT_PATH_HS			3
+#define MC_ASOC_INPUT_PATH_BT			4
+#define MC_ASOC_INPUT_PATH_VOICECALL		5
+#define MC_ASOC_INPUT_PATH_VOICEUPLINK		6
+#define MC_ASOC_INPUT_PATH_VOICEDOWNLINK	7
+#define MC_ASOC_INPUT_PATH_LIN1			8
+
+#define MC_ASOC_INCALL_MIC_MAINMIC		0
+#define MC_ASOC_INCALL_MIC_SUBMIC		1
+#define MC_ASOC_INCALL_MIC_2MIC			2
+
+#define MC_ASOC_DTMF_OUTPUT_SP			0
+#define MC_ASOC_DTMF_OUTPUT_NORMAL		1
+
+struct mc_asoc_setup {
+	struct mcdrv_dev_info info;
+	unsigned char rslot[3];
+	unsigned char tslot[3];
+};
+
+struct mc_asoc_port_params {
+	u8 rate;
+	u8 bits[SNDRV_PCM_STREAM_LAST + 1];
+	u8 pcm_mono[SNDRV_PCM_STREAM_LAST + 1];
+	u8 pcm_order[SNDRV_PCM_STREAM_LAST + 1];
+	u8 pcm_law[SNDRV_PCM_STREAM_LAST + 1];
+	u8 master;
+	u8 inv;
+	u8 srcthru;
+	u8 format;
+	u8 bckfs;
+	u8 channels;
+	u8 stream;		/* bit0: Playback, bit1: Capture */
+};
+
+struct mc_asoc_dsp_params {
+	u8 *pab_param;
+	u32 size;
+	struct mc_asoc_dsp_params *next;
+};
+
+struct mc_asoc_data {
+	int irq;
+	struct spi_device *spi;
+	struct mutex mutex;
+	struct workqueue_struct *workqueue;
+	struct work_struct work;
+	struct mc_asoc_setup setup;
+	struct mc_asoc_port_params port;
+	u8 clocksw_store;
+	struct mcdrv_path_info path_store;
+	struct mcdrv_vol_info vol_store;
+	struct mcdrv_dio_info dio_store;
+	struct mcdrv_dio_path_info diopath_store;
+	struct mcdrv_swap_info swap_store;
+	struct mcdrv_hsdet_info hsdet_store;
+	struct mc_asoc_dsp_params params_store[4][2];
+};
+
+#endif /* _YMU831_PRIV_H */
-- 
1.7.9.5



More information about the Alsa-devel mailing list