ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/sound/soc/pxa/Kconfig b/marvell/linux/sound/soc/pxa/Kconfig
new file mode 100644
index 0000000..9b36f7f
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/Kconfig
@@ -0,0 +1,263 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config SND_PXA2XX_SOC
+	tristate "SoC Audio for the Intel PXA2xx chip"
+	depends on ARCH_PXA || COMPILE_TEST
+	select SND_PXA2XX_LIB
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the PXA2xx AC97, I2S or SSP interface. You will also need
+	  to select the audio interfaces to support below.
+
+config SND_MMP_SOC
+	bool "Soc Audio for Marvell MMP chips"
+	depends on ARCH_MMP
+	select MMP_SRAM
+	select SND_SOC_GENERIC_DMAENGINE_PCM
+	select SND_ARM
+	help
+	  Say Y if you want to add support for codecs attached to
+	  the MMP SSPA interface.
+
+config SND_PXA_SOC
+	tristate "SoC Audio for MARVELL PXA chips with pdma"
+	depends on ARCH_MMP && MMP_PDMA
+	select SND_SOC_GENERIC_DMAENGINE_PCM if MMP_PDMA
+	help
+	  Say Y or M if you want to add support for ssp
+	  which uses pdma as pcm platform driver. You
+	  will also need to select the audio interfaces
+	  to support below.
+
+config SND_PXA2XX_AC97
+	tristate
+
+config SND_PXA2XX_SOC_AC97
+	tristate
+	select AC97_BUS_NEW
+	select SND_PXA2XX_LIB
+	select SND_PXA2XX_LIB_AC97
+	select SND_SOC_AC97_BUS_NEW
+
+config SND_PXA2XX_SOC_I2S
+	select SND_PXA2XX_LIB
+	tristate
+
+config SND_PXA_SOC_SSP
+	tristate "Soc Audio via PXA2xx/PXA3xx SSP ports"
+	depends on PLAT_PXA
+	select PXA_SSP
+	select SND_PXA2XX_LIB
+
+config SND_MMP_SOC_SSPA
+	tristate
+
+config SND_PXA2XX_SOC_CORGI
+	tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
+	depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-C7x0 models (Corgi, Shepherd, Husky).
+
+config SND_PXA2XX_SOC_SPITZ
+	tristate "SoC Audio support for Sharp Zaurus SL-Cxx00"
+	depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8750
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita).
+
+config SND_PXA2XX_SOC_Z2
+	tristate "SoC Audio support for Zipit Z2"
+	depends on SND_PXA2XX_SOC && MACH_ZIPIT2 && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8750
+	help
+	  Say Y if you want to add support for SoC audio on Zipit Z2.
+
+config SND_PXA2XX_SOC_POODLE
+	tristate "SoC Audio support for Poodle"
+	depends on SND_PXA2XX_SOC && MACH_POODLE && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_WM8731
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-5600 model (Poodle).
+
+config SND_PXA2XX_SOC_TOSA
+	tristate "SoC AC97 Audio support for Tosa"
+	depends on SND_PXA2XX_SOC && MACH_TOSA
+	depends on MFD_TC6393XB
+	depends on AC97_BUS=n
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for SoC audio on Sharp
+	  Zaurus SL-C6000x models (Tosa).
+
+config SND_PXA2XX_SOC_E740
+	tristate "SoC AC97 Audio support for e740"
+	depends on SND_PXA2XX_SOC && MACH_E740
+	depends on AC97_BUS=n
+	select SND_SOC_WM9705
+	select SND_PXA2XX_SOC_AC97
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  toshiba e740 PDA
+
+config SND_PXA2XX_SOC_E750
+	tristate "SoC AC97 Audio support for e750"
+	depends on SND_PXA2XX_SOC && MACH_E750
+	depends on AC97_BUS=n
+	select SND_SOC_WM9705
+	select SND_PXA2XX_SOC_AC97
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  toshiba e750 PDA
+
+config SND_PXA2XX_SOC_E800
+	tristate "SoC AC97 Audio support for e800"
+	depends on SND_PXA2XX_SOC && MACH_E800
+	depends on AC97_BUS=n
+	select SND_SOC_WM9712
+	select SND_PXA2XX_SOC_AC97
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Toshiba e800 PDA
+
+config SND_PXA2XX_SOC_EM_X270
+	tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300"
+	depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \
+			MACH_CM_X300)
+	depends on AC97_BUS=n
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for SoC audio on
+	  CompuLab EM-x270, eXeda and CM-X300 machines.
+
+config SND_PXA2XX_SOC_PALM27X
+	bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive"
+	depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \
+			MACH_PALMT5 || MACH_PALMTE2)
+	depends on AC97_BUS=n
+	select SND_PXA2XX_SOC_AC97
+	select SND_SOC_WM9712
+	help
+	  Say Y if you want to add support for SoC audio on
+	  Palm T|X, T5, E2 or LifeDrive handheld computer.
+
+config SND_PXA910_SOC
+	tristate "SoC Audio for Marvell PXA910 chip"
+	depends on ARCH_MMP && SND
+	select SND_PCM
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell PXA910 reference platform.
+
+config SND_SOC_TTC_DKB
+	tristate "SoC Audio support for TTC DKB"
+	depends on SND_PXA910_SOC && MACH_TTC_DKB && I2C=y
+	select PXA_SSP
+	select SND_PXA_SOC_SSP
+	select SND_MMP_SOC
+	select MFD_88PM860X
+	select SND_SOC_88PM860X
+	help
+	  Say Y if you want to add support for SoC audio on TTC DKB
+
+
+config SND_SOC_ZYLONITE
+	tristate "SoC Audio support for Marvell Zylonite"
+	depends on SND_PXA2XX_SOC && MACH_ZYLONITE
+	depends on AC97_BUS=n
+	select SND_PXA2XX_SOC_AC97
+	select SND_PXA_SOC_SSP
+	select SND_SOC_WM9713
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell Zylonite reference platform.
+
+config SND_PXA2XX_SOC_HX4700
+	tristate "SoC Audio support for HP iPAQ hx4700"
+	depends on SND_PXA2XX_SOC && MACH_H4700 && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_SOC_AK4641
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  HP iPAQ hx4700.
+
+config SND_PXA2XX_SOC_MAGICIAN
+	tristate "SoC Audio support for HTC Magician"
+	depends on SND_PXA2XX_SOC && MACH_MAGICIAN && I2C
+	select SND_PXA2XX_SOC_I2S
+	select SND_PXA_SOC_SSP
+	select SND_SOC_UDA1380
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  HTC Magician.
+
+config SND_PXA2XX_SOC_MIOA701
+        tristate "SoC Audio support for MIO A701"
+        depends on SND_PXA2XX_SOC && MACH_MIOA701
+	depends on AC97_BUS=n
+        select SND_PXA2XX_SOC_AC97
+        select SND_SOC_WM9713
+        help
+          Say Y if you want to add support for SoC audio on the
+          MIO A701.
+
+config SND_PXA2XX_SOC_IMOTE2
+       tristate "SoC Audio support for IMote 2"
+       depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C
+       select SND_PXA2XX_SOC_I2S
+       select SND_SOC_WM8940
+       help
+         Say Y if you want to add support for SoC audio on the
+	 IMote 2.
+
+config SND_MMP_SOC_BROWNSTONE
+	tristate "SoC Audio support for Marvell Brownstone"
+	depends on SND_MMP_SOC && MACH_BROWNSTONE && I2C
+	select SND_MMP_SOC_SSPA
+	select MFD_WM8994
+	select SND_SOC_WM8994
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  Marvell Brownstone reference platform.
+
+config SND_PXA_SSP_DUMP
+	bool "PXA SSP data dump"
+	help
+	  Say Y if you want to enable PXA ssp data dump for SoC
+	  audio on the MARVELL pxa988/1088/1L88 reference
+	  platform. currently it dumps audio data from audio
+	  buffer in sram and save it in file under /data/.
+
+config SND_SOC_PXA_NAU8810
+	bool "SoC Audio support for PXA NAU8810"
+	depends on ARCH_MMP && SND
+	select SND_PCM
+	select PXA_SSP
+	select SND_PXA_SOC_SSP
+	select SND_PXA_SSP_DUMP
+	select SND_MMP_SOC
+	select SND_PXA_SOC
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  ASR PXA NAU8810 reference platform.
+
+config SND_SOC_PXA_ALC5616
+	bool "SoC Audio support for PXA ALC5616"
+	depends on ARCH_MMP && SND
+	select SND_PCM
+	select PXA_SSP
+	select SND_PXA_SOC_SSP
+	select SND_PXA_SSP_DUMP
+	select SND_MMP_SOC
+	select SND_PXA_SOC
+	help
+	  Say Y if you want to add support for SoC audio on the
+	  ASR PXA ALC5616 reference platform.
diff --git a/marvell/linux/sound/soc/pxa/Makefile b/marvell/linux/sound/soc/pxa/Makefile
new file mode 100644
index 0000000..260efb0
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/Makefile
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: GPL-2.0
+# PXA Platform Support
+snd-soc-pxa2xx-objs := pxa2xx-pcm.o
+snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
+snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
+snd-soc-pxa-ssp-objs := pxa-ssp.o
+snd-soc-ssp-dummy-objs := ssp-dummy.o
+snd-soc-mmp-objs := mmp-pcm.o
+snd-soc-mmp-sspa-objs := mmp-sspa.o
+snd-soc-pxa-objs := pxa-pcm.o
+
+obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
+obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
+obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
+
+# PXA Machine Support
+snd-soc-corgi-objs := corgi.o
+snd-soc-poodle-objs := poodle.o
+snd-soc-tosa-objs := tosa.o
+snd-soc-e740-objs := e740_wm9705.o
+snd-soc-e750-objs := e750_wm9705.o
+snd-soc-e800-objs := e800_wm9712.o
+snd-soc-spitz-objs := spitz.o
+snd-soc-em-x270-objs := em-x270.o
+snd-soc-palm27x-objs := palm27x.o
+snd-soc-zylonite-objs := zylonite.o
+snd-soc-hx4700-objs := hx4700.o
+snd-soc-magician-objs := magician.o
+snd-soc-mioa701-objs := mioa701_wm9713.o
+snd-soc-z2-objs := z2.o
+snd-soc-imote2-objs := imote2.o
+snd-soc-brownstone-objs := brownstone.o
+snd-soc-ttc-dkb-objs := ttc-dkb.o
+
+obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o
+obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o
+obj-$(CONFIG_SND_PXA2XX_SOC_TOSA) += snd-soc-tosa.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E740) += snd-soc-e740.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E750) += snd-soc-e750.o
+obj-$(CONFIG_SND_PXA2XX_SOC_E800) += snd-soc-e800.o
+obj-$(CONFIG_SND_PXA2XX_SOC_SPITZ) += snd-soc-spitz.o
+obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
+obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
+obj-$(CONFIG_SND_PXA2XX_SOC_HX4700) += snd-soc-hx4700.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
+obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
+obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
+obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
+obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
+obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o
+obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o
+
+obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o
+obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o
+obj-$(CONFIG_SND_PXA_SOC) += snd-soc-pxa.o
+
+snd-soc-pxa-nau8810-objs := pxa-nau8810.o
+snd-soc-pxa-alc5616-objs := pxa-alc5616.o
+snd-soc-pxa-sndcard-objs := pxa-sndcard.o
+
+ifeq ($(CONFIG_LINUX_ALSA_SSP_CONTROLLER_ENABLE),y)
+
+ifeq ($(CONFIG_CODEC_PM812),y)
+obj-y += snd-soc-pxa-ssp.o
+obj-y += snd-soc-pxa-sndcard.o
+endif
+
+ifeq ($(CONFIG_CODEC_PM805),y)
+obj-y += snd-soc-pxa-ssp.o
+obj-y += snd-soc-pxa-sndcard.o
+endif
+
+ifeq ($(CONFIG_CODEC_NAU8810),y)
+obj-y += snd-soc-pxa-ssp.o
+obj-y += snd-soc-pxa-sndcard.o
+endif
+
+ifeq ($(CONFIG_CODEC_ALC5616),y)
+obj-y += snd-soc-pxa-ssp.o
+obj-y += snd-soc-pxa-sndcard.o
+endif
+
+endif
+
+ifeq ($(CONFIG_LINUX_ALSA_SSP_CONTROLLER_DISABLE),y)
+
+ifeq ($(CONFIG_MODEM_AUDIO_CONTROLLER_GSSP),y)
+ifeq ($(CONFIG_CODEC_NAU8810),y)
+obj-y += snd-soc-ssp-dummy.o
+obj-y += snd-soc-pxa-nau8810.o
+endif
+endif
+
+ifeq ($(CONFIG_MODEM_AUDIO_CONTROLLER_GSSP),y)
+ifeq ($(CONFIG_CODEC_ALC5616),y)
+obj-y += snd-soc-ssp-dummy.o
+obj-y += snd-soc-pxa-alc5616.o
+endif
+endif
+
+ifeq ($(CONFIG_MODEM_AUDIO_CONTROLLER_SSPA),y)
+ifeq ($(CONFIG_CODEC_NAU8810),y)
+obj-y += snd-soc-ssp-dummy.o
+obj-y += snd-soc-pxa-nau8810.o
+endif
+endif
+
+ifeq ($(CONFIG_MODEM_AUDIO_CONTROLLER_SSPA),y)
+ifeq ($(CONFIG_CODEC_ALC5616),y)
+obj-y += snd-soc-ssp-dummy.o
+obj-y += snd-soc-pxa-alc5616.o
+endif
+endif
+
+endif
diff --git a/marvell/linux/sound/soc/pxa/brownstone.c b/marvell/linux/sound/soc/pxa/brownstone.c
new file mode 100644
index 0000000..53b1435
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/brownstone.c
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/sound/soc/pxa/brownstone.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ */
+
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include "../codecs/wm8994.h"
+#include "mmp-sspa.h"
+
+static const struct snd_kcontrol_new brownstone_dapm_control[] = {
+	SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static const struct snd_soc_dapm_widget brownstone_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Main Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route brownstone_audio_map[] = {
+	{"Ext Spk", NULL, "SPKOUTLP"},
+	{"Ext Spk", NULL, "SPKOUTLN"},
+	{"Ext Spk", NULL, "SPKOUTRP"},
+	{"Ext Spk", NULL, "SPKOUTRN"},
+
+	{"Headset Stereophone", NULL, "HPOUT1L"},
+	{"Headset Stereophone", NULL, "HPOUT1R"},
+
+	{"IN1RN", NULL, "Headset Mic"},
+
+	{"DMIC1DAT", NULL, "MICBIAS1"},
+	{"MICBIAS1", NULL, "Main Mic"},
+};
+
+static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int freq_out, sspa_mclk, sysclk;
+
+	if (params_rate(params) > 11025) {
+		freq_out  = params_rate(params) * 512;
+		sysclk    = params_rate(params) * 256;
+		sspa_mclk = params_rate(params) * 64;
+	} else {
+		freq_out  = params_rate(params) * 1024;
+		sysclk    = params_rate(params) * 512;
+		sspa_mclk = params_rate(params) * 64;
+	}
+
+	snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0);
+	snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk);
+	snd_soc_dai_set_pll(cpu_dai, MMP_SSPA_CLK, 0, freq_out, sspa_mclk);
+
+	/* set wm8994 sysclk */
+	snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, sysclk, 0);
+
+	return 0;
+}
+
+/* machine stream operations */
+static const struct snd_soc_ops brownstone_ops = {
+	.hw_params = brownstone_wm8994_hw_params,
+};
+
+SND_SOC_DAILINK_DEFS(wm8994,
+	DAILINK_COMP_ARRAY(COMP_CPU("mmp-sspa-dai.0")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm8994-codec", "wm8994-aif1")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("mmp-pcm-audio")));
+
+static struct snd_soc_dai_link brownstone_wm8994_dai[] = {
+{
+	.name		= "WM8994",
+	.stream_name	= "WM8994 HiFi",
+	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				SND_SOC_DAIFMT_CBS_CFS,
+	.ops		= &brownstone_ops,
+	SND_SOC_DAILINK_REG(wm8994),
+},
+};
+
+/* audio machine driver */
+static struct snd_soc_card brownstone = {
+	.name         = "brownstone",
+	.owner        = THIS_MODULE,
+	.dai_link     = brownstone_wm8994_dai,
+	.num_links    = ARRAY_SIZE(brownstone_wm8994_dai),
+
+	.controls = brownstone_dapm_control,
+	.num_controls = ARRAY_SIZE(brownstone_dapm_control),
+	.dapm_widgets = brownstone_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets),
+	.dapm_routes = brownstone_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(brownstone_audio_map),
+	.fully_routed = true,
+};
+
+static int brownstone_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	brownstone.dev = &pdev->dev;
+	ret = devm_snd_soc_register_card(&pdev->dev, &brownstone);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+				ret);
+	return ret;
+}
+
+static struct platform_driver mmp_driver = {
+	.driver		= {
+		.name	= "brownstone-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= brownstone_probe,
+};
+
+module_platform_driver(mmp_driver);
+
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC Brownstone");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:brownstone-audio");
diff --git a/marvell/linux/sound/soc/pxa/corgi.c b/marvell/linux/sound/soc/pxa/corgi.c
new file mode 100644
index 0000000..d810823
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/corgi.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * corgi.c  --  SoC audio for Corgi
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *          Richard Purdie <richard@openedhand.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/corgi.h>
+#include <mach/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-i2s.h"
+
+#define CORGI_HP        0
+#define CORGI_MIC       1
+#define CORGI_LINE      2
+#define CORGI_HEADSET   3
+#define CORGI_HP_OFF    4
+#define CORGI_SPK_ON    0
+#define CORGI_SPK_OFF   1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define CORGI_AUDIO_CLOCK 12288000
+
+static int corgi_jack_func;
+static int corgi_spk_func;
+
+static void corgi_ext_control(struct snd_soc_dapm_context *dapm)
+{
+	snd_soc_dapm_mutex_lock(dapm);
+
+	/* set up jack connection */
+	switch (corgi_jack_func) {
+	case CORGI_HP:
+		/* set = unmute headphone */
+		gpio_set_value(CORGI_GPIO_MUTE_L, 1);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 1);
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	case CORGI_MIC:
+		/* reset = mute headphone */
+		gpio_set_value(CORGI_GPIO_MUTE_L, 0);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 0);
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	case CORGI_LINE:
+		gpio_set_value(CORGI_GPIO_MUTE_L, 0);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 0);
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	case CORGI_HEADSET:
+		gpio_set_value(CORGI_GPIO_MUTE_L, 0);
+		gpio_set_value(CORGI_GPIO_MUTE_R, 1);
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	}
+
+	if (corgi_spk_func == CORGI_SPK_ON)
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
+	else
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
+
+	/* signal a DAPM event */
+	snd_soc_dapm_sync_unlocked(dapm);
+
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static int corgi_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* check the jack status at stream startup */
+	corgi_ext_control(&rtd->card->dapm);
+
+	return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on corgi */
+static void corgi_shutdown(struct snd_pcm_substream *substream)
+{
+	/* set = unmute headphone */
+	gpio_set_value(CORGI_GPIO_MUTE_L, 1);
+	gpio_set_value(CORGI_GPIO_MUTE_R, 1);
+}
+
+static int corgi_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_ops corgi_ops = {
+	.startup = corgi_startup,
+	.hw_params = corgi_hw_params,
+	.shutdown = corgi_shutdown,
+};
+
+static int corgi_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = corgi_jack_func;
+	return 0;
+}
+
+static int corgi_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (corgi_jack_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	corgi_jack_func = ucontrol->value.enumerated.item[0];
+	corgi_ext_control(&card->dapm);
+	return 1;
+}
+
+static int corgi_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = corgi_spk_func;
+	return 0;
+}
+
+static int corgi_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
+
+	if (corgi_spk_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	corgi_spk_func = ucontrol->value.enumerated.item[0];
+	corgi_ext_control(&card->dapm);
+	return 1;
+}
+
+static int corgi_amp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(CORGI_GPIO_APM_ON, SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+static int corgi_mic_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(CORGI_GPIO_MIC_BIAS, SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+/* corgi machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_MIC("Mic Jack", corgi_mic_event),
+SND_SOC_DAPM_SPK("Ext Spk", corgi_amp_event),
+SND_SOC_DAPM_LINE("Line Jack", NULL),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Corgi machine audio map (connections to the codec pins) */
+static const struct snd_soc_dapm_route corgi_audio_map[] = {
+
+	/* headset Jack  - in = micin, out = LHPOUT*/
+	{"Headset Jack", NULL, "LHPOUT"},
+
+	/* headphone connected to LHPOUT1, RHPOUT1 */
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	/* speaker connected to LOUT, ROUT */
+	{"Ext Spk", NULL, "ROUT"},
+	{"Ext Spk", NULL, "LOUT"},
+
+	/* mic is connected to MICIN (via right channel of headphone jack) */
+	{"MICIN", NULL, "Mic Jack"},
+
+	/* Same as the above but no mic bias for line signals */
+	{"MICIN", NULL, "Line Jack"},
+};
+
+static const char * const jack_function[] = {"Headphone", "Mic", "Line",
+	"Headset", "Off"};
+static const char * const spk_function[] = {"On", "Off"};
+static const struct soc_enum corgi_enum[] = {
+	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8731_corgi_controls[] = {
+	SOC_ENUM_EXT("Jack Function", corgi_enum[0], corgi_get_jack,
+		corgi_set_jack),
+	SOC_ENUM_EXT("Speaker Function", corgi_enum[1], corgi_get_spk,
+		corgi_set_spk),
+};
+
+/* corgi digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(wm8731,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link corgi_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+	.ops = &corgi_ops,
+	SND_SOC_DAILINK_REG(wm8731),
+};
+
+/* corgi audio machine driver */
+static struct snd_soc_card corgi = {
+	.name = "Corgi",
+	.owner = THIS_MODULE,
+	.dai_link = &corgi_dai,
+	.num_links = 1,
+
+	.controls = wm8731_corgi_controls,
+	.num_controls = ARRAY_SIZE(wm8731_corgi_controls),
+	.dapm_widgets = wm8731_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+	.dapm_routes = corgi_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(corgi_audio_map),
+	.fully_routed = true,
+};
+
+static int corgi_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &corgi;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+	return ret;
+}
+
+static struct platform_driver corgi_driver = {
+	.driver		= {
+		.name	= "corgi-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= corgi_probe,
+};
+
+module_platform_driver(corgi_driver);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Corgi");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:corgi-audio");
diff --git a/marvell/linux/sound/soc/pxa/e740_wm9705.c b/marvell/linux/sound/soc/pxa/e740_wm9705.c
new file mode 100644
index 0000000..eafa148
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/e740_wm9705.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * e740-wm9705.c  --  SoC audio for e740
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/mach-types.h>
+
+#define E740_AUDIO_OUT 1
+#define E740_AUDIO_IN  2
+
+static int e740_audio_power;
+
+static void e740_sync_audio_power(int status)
+{
+	gpio_set_value(GPIO_E740_WM9705_nAVDD2, !status);
+	gpio_set_value(GPIO_E740_AMP_ON, (status & E740_AUDIO_OUT) ? 1 : 0);
+	gpio_set_value(GPIO_E740_MIC_ON, (status & E740_AUDIO_IN) ? 1 : 0);
+}
+
+static int e740_mic_amp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		e740_audio_power |= E740_AUDIO_IN;
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		e740_audio_power &= ~E740_AUDIO_IN;
+
+	e740_sync_audio_power(e740_audio_power);
+
+	return 0;
+}
+
+static int e740_output_amp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		e740_audio_power |= E740_AUDIO_OUT;
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		e740_audio_power &= ~E740_AUDIO_OUT;
+
+	e740_sync_audio_power(e740_audio_power);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget e740_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+	SND_SOC_DAPM_PGA_E("Output Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+			e740_output_amp_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("Mic Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+			e740_mic_amp_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Output Amp", NULL, "LOUT"},
+	{"Output Amp", NULL, "ROUT"},
+	{"Output Amp", NULL, "MONOOUT"},
+
+	{"Speaker", NULL, "Output Amp"},
+	{"Headphone Jack", NULL, "Output Amp"},
+
+	{"MIC1", NULL, "Mic Amp"},
+	{"Mic Amp", NULL, "Mic (Internal)"},
+};
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9705-codec", "wm9705-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9705-codec", "wm9705-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link e740_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		SND_SOC_DAILINK_REG(ac97),
+	},
+	{
+		.name = "AC97 Aux",
+		.stream_name = "AC97 Aux",
+		SND_SOC_DAILINK_REG(ac97_aux),
+	},
+};
+
+static struct snd_soc_card e740 = {
+	.name = "Toshiba e740",
+	.owner = THIS_MODULE,
+	.dai_link = e740_dai,
+	.num_links = ARRAY_SIZE(e740_dai),
+
+	.dapm_widgets = e740_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.fully_routed = true,
+};
+
+static struct gpio e740_audio_gpios[] = {
+	{ GPIO_E740_MIC_ON, GPIOF_OUT_INIT_LOW, "Mic amp" },
+	{ GPIO_E740_AMP_ON, GPIOF_OUT_INIT_LOW, "Output amp" },
+	{ GPIO_E740_WM9705_nAVDD2, GPIOF_OUT_INIT_HIGH, "Audio power" },
+};
+
+static int e740_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &e740;
+	int ret;
+
+	ret = gpio_request_array(e740_audio_gpios,
+				 ARRAY_SIZE(e740_audio_gpios));
+	if (ret)
+		return ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios));
+	}
+	return ret;
+}
+
+static int e740_remove(struct platform_device *pdev)
+{
+	gpio_free_array(e740_audio_gpios, ARRAY_SIZE(e740_audio_gpios));
+	return 0;
+}
+
+static struct platform_driver e740_driver = {
+	.driver		= {
+		.name	= "e740-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= e740_probe,
+	.remove		= e740_remove,
+};
+
+module_platform_driver(e740_driver);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e740");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:e740-audio");
diff --git a/marvell/linux/sound/soc/pxa/e750_wm9705.c b/marvell/linux/sound/soc/pxa/e750_wm9705.c
new file mode 100644
index 0000000..d75510d
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/e750_wm9705.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * e750-wm9705.c  --  SoC audio for e750
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+#include <asm/mach-types.h>
+
+static int e750_spk_amp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		gpio_set_value(GPIO_E750_SPK_AMP_OFF, 0);
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		gpio_set_value(GPIO_E750_SPK_AMP_OFF, 1);
+
+	return 0;
+}
+
+static int e750_hp_amp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		gpio_set_value(GPIO_E750_HP_AMP_OFF, 0);
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		gpio_set_value(GPIO_E750_HP_AMP_OFF, 1);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget e750_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+	SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+			e750_hp_amp_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+			e750_spk_amp_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Amp", NULL, "HPOUTL"},
+	{"Headphone Amp", NULL, "HPOUTR"},
+	{"Headphone Jack", NULL, "Headphone Amp"},
+
+	{"Speaker Amp", NULL, "MONOOUT"},
+	{"Speaker", NULL, "Speaker Amp"},
+
+	{"MIC1", NULL, "Mic (Internal)"},
+};
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9705-codec", "wm9705-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9705-codec", "wm9705-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link e750_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		SND_SOC_DAILINK_REG(ac97),
+		/* use ops to check startup state */
+	},
+	{
+		.name = "AC97 Aux",
+		.stream_name = "AC97 Aux",
+		SND_SOC_DAILINK_REG(ac97_aux),
+	},
+};
+
+static struct snd_soc_card e750 = {
+	.name = "Toshiba e750",
+	.owner = THIS_MODULE,
+	.dai_link = e750_dai,
+	.num_links = ARRAY_SIZE(e750_dai),
+
+	.dapm_widgets = e750_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.fully_routed = true,
+};
+
+static struct gpio e750_audio_gpios[] = {
+	{ GPIO_E750_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Headphone amp" },
+	{ GPIO_E750_SPK_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" },
+};
+
+static int e750_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &e750;
+	int ret;
+
+	ret = gpio_request_array(e750_audio_gpios,
+				 ARRAY_SIZE(e750_audio_gpios));
+	if (ret)
+		return ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios));
+	}
+	return ret;
+}
+
+static int e750_remove(struct platform_device *pdev)
+{
+	gpio_free_array(e750_audio_gpios, ARRAY_SIZE(e750_audio_gpios));
+	return 0;
+}
+
+static struct platform_driver e750_driver = {
+	.driver		= {
+		.name	= "e750-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= e750_probe,
+	.remove		= e750_remove,
+};
+
+module_platform_driver(e750_driver);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e750");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:e750-audio");
diff --git a/marvell/linux/sound/soc/pxa/e800_wm9712.c b/marvell/linux/sound/soc/pxa/e800_wm9712.c
new file mode 100644
index 0000000..56d543d
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/e800_wm9712.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * e800-wm9712.c  --  SoC audio for e800
+ *
+ * Copyright 2007 (c) Ian Molton <spyro@f2s.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+#include <mach/eseries-gpio.h>
+
+static int e800_spk_amp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		gpio_set_value(GPIO_E800_SPK_AMP_ON, 1);
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		gpio_set_value(GPIO_E800_SPK_AMP_ON, 0);
+
+	return 0;
+}
+
+static int e800_hp_amp_event(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *kcontrol, int event)
+{
+	if (event & SND_SOC_DAPM_PRE_PMU)
+		gpio_set_value(GPIO_E800_HP_AMP_OFF, 0);
+	else if (event & SND_SOC_DAPM_POST_PMD)
+		gpio_set_value(GPIO_E800_HP_AMP_OFF, 1);
+
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget e800_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic (Internal1)", NULL),
+	SND_SOC_DAPM_MIC("Mic (Internal2)", NULL),
+	SND_SOC_DAPM_SPK("Speaker", NULL),
+	SND_SOC_DAPM_PGA_E("Headphone Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+			e800_hp_amp_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+	SND_SOC_DAPM_PGA_E("Speaker Amp", SND_SOC_NOPM, 0, 0, NULL, 0,
+			e800_spk_amp_event, SND_SOC_DAPM_PRE_PMU |
+			SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Headphone Jack", NULL, "HPOUTR"},
+	{"Headphone Jack", NULL, "Headphone Amp"},
+
+	{"Speaker Amp", NULL, "MONOOUT"},
+	{"Speaker", NULL, "Speaker Amp"},
+
+	{"MIC1", NULL, "Mic (Internal1)"},
+	{"MIC2", NULL, "Mic (Internal2)"},
+};
+
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link e800_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		SND_SOC_DAILINK_REG(ac97),
+	},
+	{
+		.name = "AC97 Aux",
+		.stream_name = "AC97 Aux",
+		SND_SOC_DAILINK_REG(ac97_aux),
+	},
+};
+
+static struct snd_soc_card e800 = {
+	.name = "Toshiba e800",
+	.owner = THIS_MODULE,
+	.dai_link = e800_dai,
+	.num_links = ARRAY_SIZE(e800_dai),
+
+	.dapm_widgets = e800_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(e800_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static struct gpio e800_audio_gpios[] = {
+	{ GPIO_E800_SPK_AMP_ON, GPIOF_OUT_INIT_HIGH, "Headphone amp" },
+	{ GPIO_E800_HP_AMP_OFF, GPIOF_OUT_INIT_HIGH, "Speaker amp" },
+};
+
+static int e800_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &e800;
+	int ret;
+
+	ret = gpio_request_array(e800_audio_gpios,
+				 ARRAY_SIZE(e800_audio_gpios));
+	if (ret)
+		return ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios));
+	}
+	return ret;
+}
+
+static int e800_remove(struct platform_device *pdev)
+{
+	gpio_free_array(e800_audio_gpios, ARRAY_SIZE(e800_audio_gpios));
+	return 0;
+}
+
+static struct platform_driver e800_driver = {
+	.driver		= {
+		.name	= "e800-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= e800_probe,
+	.remove		= e800_remove,
+};
+
+module_platform_driver(e800_driver);
+
+/* Module information */
+MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
+MODULE_DESCRIPTION("ALSA SoC driver for e800");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:e800-audio");
diff --git a/marvell/linux/sound/soc/pxa/em-x270.c b/marvell/linux/sound/soc/pxa/em-x270.c
new file mode 100644
index 0000000..9076ea7
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/em-x270.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SoC audio driver for EM-X270, eXeda and CM-X300
+ *
+ * Copyright 2007, 2009 CompuLab, Ltd.
+ *
+ * Author: Mike Rapoport <mike@compulab.co.il>
+ *
+ * Copied from tosa.c:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *          Richard Purdie <richard@openedhand.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link em_x270_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		SND_SOC_DAILINK_REG(ac97),
+	},
+	{
+		.name = "AC97 Aux",
+		.stream_name = "AC97 Aux",
+		SND_SOC_DAILINK_REG(ac97_aux),
+	},
+};
+
+static struct snd_soc_card em_x270 = {
+	.name = "EM-X270",
+	.owner = THIS_MODULE,
+	.dai_link = em_x270_dai,
+	.num_links = ARRAY_SIZE(em_x270_dai),
+};
+
+static struct platform_device *em_x270_snd_device;
+
+static int __init em_x270_init(void)
+{
+	int ret;
+
+	if (!(machine_is_em_x270() || machine_is_exeda()
+	      || machine_is_cm_x300()))
+		return -ENODEV;
+
+	em_x270_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!em_x270_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(em_x270_snd_device, &em_x270);
+	ret = platform_device_add(em_x270_snd_device);
+
+	if (ret)
+		platform_device_put(em_x270_snd_device);
+
+	return ret;
+}
+
+static void __exit em_x270_exit(void)
+{
+	platform_device_unregister(em_x270_snd_device);
+}
+
+module_init(em_x270_init);
+module_exit(em_x270_exit);
+
+/* Module information */
+MODULE_AUTHOR("Mike Rapoport");
+MODULE_DESCRIPTION("ALSA SoC EM-X270, eXeda and CM-X300");
+MODULE_LICENSE("GPL");
diff --git a/marvell/linux/sound/soc/pxa/hx4700.c b/marvell/linux/sound/soc/pxa/hx4700.c
new file mode 100644
index 0000000..0139343
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/hx4700.c
@@ -0,0 +1,214 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SoC audio for HP iPAQ hx4700
+ *
+ * Copyright (c) 2009 Philipp Zabel
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/hx4700.h>
+#include <asm/mach-types.h>
+#include "pxa2xx-i2s.h"
+
+static struct snd_soc_jack hs_jack;
+
+/* Headphones jack detection DAPM pin */
+static struct snd_soc_jack_pin hs_jack_pin[] = {
+	{
+		.pin	= "Headphone Jack",
+		.mask	= SND_JACK_HEADPHONE,
+	},
+	{
+		.pin	= "Speaker",
+		/* disable speaker when hp jack is inserted */
+		.mask   = SND_JACK_HEADPHONE,
+		.invert	= 1,
+	},
+};
+
+/* Headphones jack detection GPIO */
+static struct snd_soc_jack_gpio hs_jack_gpio = {
+	.gpio		= GPIO75_HX4700_EARPHONE_nDET,
+	.invert		= true,
+	.name		= "hp-gpio",
+	.report		= SND_JACK_HEADPHONE,
+	.debounce_time	= 200,
+};
+
+/*
+ * iPAQ hx4700 uses I2S for capture and playback.
+ */
+static int hx4700_hw_params(struct snd_pcm_substream *substream,
+			    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+
+	/* set the I2S system clock as output */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	/* inform codec driver about clock freq *
+	 * (PXA I2S always uses divider 256)    */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 256 * params_rate(params),
+			SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_ops hx4700_ops = {
+	.hw_params = hx4700_hw_params,
+};
+
+static int hx4700_spk_power(struct snd_soc_dapm_widget *w,
+			    struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(GPIO107_HX4700_SPK_nSD, !!SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+static int hx4700_hp_power(struct snd_soc_dapm_widget *w,
+			   struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(GPIO92_HX4700_HP_DRIVER, !!SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+/* hx4700 machine dapm widgets */
+static const struct snd_soc_dapm_widget hx4700_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", hx4700_hp_power),
+	SND_SOC_DAPM_SPK("Speaker", hx4700_spk_power),
+	SND_SOC_DAPM_MIC("Built-in Microphone", NULL),
+};
+
+/* hx4700 machine audio_map */
+static const struct snd_soc_dapm_route hx4700_audio_map[] = {
+
+	/* Headphone connected to LOUT, ROUT */
+	{"Headphone Jack", NULL, "LOUT"},
+	{"Headphone Jack", NULL, "ROUT"},
+
+	/* Speaker connected to MOUT2 */
+	{"Speaker", NULL, "MOUT2"},
+
+	/* Microphone connected to MICIN */
+	{"MICIN", NULL, "Built-in Microphone"},
+	{"AIN", NULL, "MICOUT"},
+};
+
+/*
+ * Logic for a ak4641 as connected on a HP iPAQ hx4700
+ */
+static int hx4700_ak4641_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+
+	/* Jack detection API stuff */
+	err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+				    SND_JACK_HEADPHONE, &hs_jack, hs_jack_pin,
+				    ARRAY_SIZE(hs_jack_pin));
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_gpios(&hs_jack, 1, &hs_jack_gpio);
+
+	return err;
+}
+
+/* hx4700 digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(ak4641,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("ak4641.0-0012", "ak4641-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link hx4700_dai = {
+	.name = "ak4641",
+	.stream_name = "AK4641",
+	.init = hx4700_ak4641_init,
+	.dai_fmt = SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+	.ops = &hx4700_ops,
+	SND_SOC_DAILINK_REG(ak4641),
+};
+
+/* hx4700 audio machine driver */
+static struct snd_soc_card snd_soc_card_hx4700 = {
+	.name			= "iPAQ hx4700",
+	.owner			= THIS_MODULE,
+	.dai_link		= &hx4700_dai,
+	.num_links		= 1,
+	.dapm_widgets		= hx4700_dapm_widgets,
+	.num_dapm_widgets	= ARRAY_SIZE(hx4700_dapm_widgets),
+	.dapm_routes		= hx4700_audio_map,
+	.num_dapm_routes	= ARRAY_SIZE(hx4700_audio_map),
+	.fully_routed		= true,
+};
+
+static struct gpio hx4700_audio_gpios[] = {
+	{ GPIO107_HX4700_SPK_nSD, GPIOF_OUT_INIT_HIGH, "SPK_POWER" },
+	{ GPIO92_HX4700_HP_DRIVER, GPIOF_OUT_INIT_LOW, "EP_POWER" },
+};
+
+static int hx4700_audio_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!machine_is_h4700())
+		return -ENODEV;
+
+	ret = gpio_request_array(hx4700_audio_gpios,
+				ARRAY_SIZE(hx4700_audio_gpios));
+	if (ret)
+		return ret;
+
+	snd_soc_card_hx4700.dev = &pdev->dev;
+	ret = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_hx4700);
+	if (ret)
+		gpio_free_array(hx4700_audio_gpios,
+				ARRAY_SIZE(hx4700_audio_gpios));
+
+	return ret;
+}
+
+static int hx4700_audio_remove(struct platform_device *pdev)
+{
+	gpio_set_value(GPIO92_HX4700_HP_DRIVER, 0);
+	gpio_set_value(GPIO107_HX4700_SPK_nSD, 0);
+
+	gpio_free_array(hx4700_audio_gpios, ARRAY_SIZE(hx4700_audio_gpios));
+	return 0;
+}
+
+static struct platform_driver hx4700_audio_driver = {
+	.driver	= {
+		.name = "hx4700-audio",
+		.pm = &snd_soc_pm_ops,
+	},
+	.probe	= hx4700_audio_probe,
+	.remove	= hx4700_audio_remove,
+};
+
+module_platform_driver(hx4700_audio_driver);
+
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_DESCRIPTION("ALSA SoC iPAQ hx4700");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hx4700-audio");
diff --git a/marvell/linux/sound/soc/pxa/imote2.c b/marvell/linux/sound/soc/pxa/imote2.c
new file mode 100644
index 0000000..514e177
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/imote2.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/module.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+
+#include "../codecs/wm8940.h"
+#include "pxa2xx-i2s.h"
+
+static int imote2_asoc_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int clk = 0;
+	int ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, clk,
+		SND_SOC_CLOCK_OUT);
+
+	return ret;
+}
+
+static const struct snd_soc_ops imote2_asoc_ops = {
+	.hw_params = imote2_asoc_hw_params,
+};
+
+SND_SOC_DAILINK_DEFS(wm8940,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm8940-codec.0-0034",
+				      "wm8940-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link imote2_dai = {
+	.name = "WM8940",
+	.stream_name = "WM8940",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+	.ops = &imote2_asoc_ops,
+	SND_SOC_DAILINK_REG(wm8940),
+};
+
+static struct snd_soc_card imote2 = {
+	.name = "Imote2",
+	.owner = THIS_MODULE,
+	.dai_link = &imote2_dai,
+	.num_links = 1,
+};
+
+static int imote2_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &imote2;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+	return ret;
+}
+
+static struct platform_driver imote2_driver = {
+	.driver		= {
+		.name	= "imote2-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= imote2_probe,
+};
+
+module_platform_driver(imote2_driver);
+
+MODULE_AUTHOR("Jonathan Cameron");
+MODULE_DESCRIPTION("ALSA SoC Imote 2");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imote2-audio");
diff --git a/marvell/linux/sound/soc/pxa/magician.c b/marvell/linux/sound/soc/pxa/magician.c
new file mode 100644
index 0000000..6483cff
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/magician.c
@@ -0,0 +1,433 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * SoC audio for HTC Magician
+ *
+ * Copyright (c) 2006 Philipp Zabel <philipp.zabel@gmail.com>
+ *
+ * based on spitz.c,
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *          Richard Purdie <richard@openedhand.com>
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/uda1380.h>
+
+#include <mach/magician.h>
+#include <asm/mach-types.h>
+#include "../codecs/uda1380.h"
+#include "pxa2xx-i2s.h"
+#include "pxa-ssp.h"
+
+#define MAGICIAN_MIC       0
+#define MAGICIAN_MIC_EXT   1
+
+static int magician_hp_switch;
+static int magician_spk_switch = 1;
+static int magician_in_sel = MAGICIAN_MIC;
+
+static void magician_ext_control(struct snd_soc_dapm_context *dapm)
+{
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	if (magician_spk_switch)
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
+	else
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+	if (magician_hp_switch)
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+	else
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+
+	switch (magician_in_sel) {
+	case MAGICIAN_MIC:
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic");
+		break;
+	case MAGICIAN_MIC_EXT:
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic");
+		break;
+	}
+
+	snd_soc_dapm_sync_unlocked(dapm);
+
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static int magician_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* check the jack status at stream startup */
+	magician_ext_control(&rtd->card->dapm);
+
+	return 0;
+}
+
+/*
+ * Magician uses SSP port for playback.
+ */
+static int magician_playback_hw_params(struct snd_pcm_substream *substream,
+				       struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int width;
+	int ret = 0;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_MSB |
+			SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A |
+			SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	width = snd_pcm_format_physical_width(params_format(params));
+	ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width);
+	if (ret < 0)
+		return ret;
+
+	/* set audio clock as clock source */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/*
+ * Magician uses I2S for capture.
+ */
+static int magician_capture_hw_params(struct snd_pcm_substream *substream,
+				      struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int ret = 0;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai,
+			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai,
+			SND_SOC_DAIFMT_MSB | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as output */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+			SND_SOC_CLOCK_OUT);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_ops magician_capture_ops = {
+	.startup = magician_startup,
+	.hw_params = magician_capture_hw_params,
+};
+
+static const struct snd_soc_ops magician_playback_ops = {
+	.startup = magician_startup,
+	.hw_params = magician_playback_hw_params,
+};
+
+static int magician_get_hp(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = magician_hp_switch;
+	return 0;
+}
+
+static int magician_set_hp(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (magician_hp_switch == ucontrol->value.integer.value[0])
+		return 0;
+
+	magician_hp_switch = ucontrol->value.integer.value[0];
+	magician_ext_control(&card->dapm);
+	return 1;
+}
+
+static int magician_get_spk(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.integer.value[0] = magician_spk_switch;
+	return 0;
+}
+
+static int magician_set_spk(struct snd_kcontrol *kcontrol,
+			    struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (magician_spk_switch == ucontrol->value.integer.value[0])
+		return 0;
+
+	magician_spk_switch = ucontrol->value.integer.value[0];
+	magician_ext_control(&card->dapm);
+	return 1;
+}
+
+static int magician_get_input(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = magician_in_sel;
+	return 0;
+}
+
+static int magician_set_input(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_value *ucontrol)
+{
+	if (magician_in_sel == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	magician_in_sel = ucontrol->value.enumerated.item[0];
+
+	switch (magician_in_sel) {
+	case MAGICIAN_MIC:
+		gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 1);
+		break;
+	case MAGICIAN_MIC_EXT:
+		gpio_set_value(EGPIO_MAGICIAN_IN_SEL1, 0);
+	}
+
+	return 1;
+}
+
+static int magician_spk_power(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+static int magician_hp_power(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+static int magician_mic_bias(struct snd_soc_dapm_widget *w,
+				struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+/* magician machine dapm widgets */
+static const struct snd_soc_dapm_widget uda1380_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", magician_hp_power),
+	SND_SOC_DAPM_SPK("Speaker", magician_spk_power),
+	SND_SOC_DAPM_MIC("Call Mic", magician_mic_bias),
+	SND_SOC_DAPM_MIC("Headset Mic", magician_mic_bias),
+};
+
+/* magician machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	/* Headphone connected to VOUTL, VOUTR */
+	{"Headphone Jack", NULL, "VOUTL"},
+	{"Headphone Jack", NULL, "VOUTR"},
+
+	/* Speaker connected to VOUTL, VOUTR */
+	{"Speaker", NULL, "VOUTL"},
+	{"Speaker", NULL, "VOUTR"},
+
+	/* Mics are connected to VINM */
+	{"VINM", NULL, "Headset Mic"},
+	{"VINM", NULL, "Call Mic"},
+};
+
+static const char * const input_select[] = {"Call Mic", "Headset Mic"};
+static const struct soc_enum magician_in_sel_enum =
+	SOC_ENUM_SINGLE_EXT(2, input_select);
+
+static const struct snd_kcontrol_new uda1380_magician_controls[] = {
+	SOC_SINGLE_BOOL_EXT("Headphone Switch",
+			(unsigned long)&magician_hp_switch,
+			magician_get_hp, magician_set_hp),
+	SOC_SINGLE_BOOL_EXT("Speaker Switch",
+			(unsigned long)&magician_spk_switch,
+			magician_get_spk, magician_set_spk),
+	SOC_ENUM_EXT("Input Select", magician_in_sel_enum,
+			magician_get_input, magician_set_input),
+};
+
+/* magician digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(playback,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.0")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-0018",
+				      "uda1380-hifi-playback")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(capture,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("uda1380-codec.0-0018",
+				      "uda1380-hifi-capture")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link magician_dai[] = {
+{
+	.name = "uda1380",
+	.stream_name = "UDA1380 Playback",
+	.ops = &magician_playback_ops,
+	SND_SOC_DAILINK_REG(playback),
+},
+{
+	.name = "uda1380",
+	.stream_name = "UDA1380 Capture",
+	.ops = &magician_capture_ops,
+	SND_SOC_DAILINK_REG(capture),
+}
+};
+
+/* magician audio machine driver */
+static struct snd_soc_card snd_soc_card_magician = {
+	.name = "Magician",
+	.owner = THIS_MODULE,
+	.dai_link = magician_dai,
+	.num_links = ARRAY_SIZE(magician_dai),
+
+	.controls = uda1380_magician_controls,
+	.num_controls = ARRAY_SIZE(uda1380_magician_controls),
+	.dapm_widgets = uda1380_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(uda1380_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.fully_routed = true,
+};
+
+static struct platform_device *magician_snd_device;
+
+/*
+ * FIXME: move into magician board file once merged into the pxa tree
+ */
+static struct uda1380_platform_data uda1380_info = {
+	.gpio_power = EGPIO_MAGICIAN_CODEC_POWER,
+	.gpio_reset = EGPIO_MAGICIAN_CODEC_RESET,
+	.dac_clk    = UDA1380_DAC_CLK_WSPLL,
+};
+
+static struct i2c_board_info i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("uda1380", 0x18),
+		.platform_data = &uda1380_info,
+	},
+};
+
+static int __init magician_init(void)
+{
+	int ret;
+	struct i2c_adapter *adapter;
+	struct i2c_client *client;
+
+	if (!machine_is_magician())
+		return -ENODEV;
+
+	adapter = i2c_get_adapter(0);
+	if (!adapter)
+		return -ENODEV;
+	client = i2c_new_device(adapter, i2c_board_info);
+	i2c_put_adapter(adapter);
+	if (!client)
+		return -ENODEV;
+
+	ret = gpio_request(EGPIO_MAGICIAN_SPK_POWER, "SPK_POWER");
+	if (ret)
+		goto err_request_spk;
+	ret = gpio_request(EGPIO_MAGICIAN_EP_POWER, "EP_POWER");
+	if (ret)
+		goto err_request_ep;
+	ret = gpio_request(EGPIO_MAGICIAN_MIC_POWER, "MIC_POWER");
+	if (ret)
+		goto err_request_mic;
+	ret = gpio_request(EGPIO_MAGICIAN_IN_SEL0, "IN_SEL0");
+	if (ret)
+		goto err_request_in_sel0;
+	ret = gpio_request(EGPIO_MAGICIAN_IN_SEL1, "IN_SEL1");
+	if (ret)
+		goto err_request_in_sel1;
+
+	gpio_set_value(EGPIO_MAGICIAN_IN_SEL0, 0);
+
+	magician_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!magician_snd_device) {
+		ret = -ENOMEM;
+		goto err_pdev;
+	}
+
+	platform_set_drvdata(magician_snd_device, &snd_soc_card_magician);
+	ret = platform_device_add(magician_snd_device);
+	if (ret) {
+		platform_device_put(magician_snd_device);
+		goto err_pdev;
+	}
+
+	return 0;
+
+err_pdev:
+	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
+err_request_in_sel1:
+	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
+err_request_in_sel0:
+	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
+err_request_mic:
+	gpio_free(EGPIO_MAGICIAN_EP_POWER);
+err_request_ep:
+	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
+err_request_spk:
+	return ret;
+}
+
+static void __exit magician_exit(void)
+{
+	platform_device_unregister(magician_snd_device);
+
+	gpio_set_value(EGPIO_MAGICIAN_SPK_POWER, 0);
+	gpio_set_value(EGPIO_MAGICIAN_EP_POWER, 0);
+	gpio_set_value(EGPIO_MAGICIAN_MIC_POWER, 0);
+
+	gpio_free(EGPIO_MAGICIAN_IN_SEL1);
+	gpio_free(EGPIO_MAGICIAN_IN_SEL0);
+	gpio_free(EGPIO_MAGICIAN_MIC_POWER);
+	gpio_free(EGPIO_MAGICIAN_EP_POWER);
+	gpio_free(EGPIO_MAGICIAN_SPK_POWER);
+}
+
+module_init(magician_init);
+module_exit(magician_exit);
+
+MODULE_AUTHOR("Philipp Zabel");
+MODULE_DESCRIPTION("ALSA SoC Magician");
+MODULE_LICENSE("GPL");
diff --git a/marvell/linux/sound/soc/pxa/mioa701_wm9713.c b/marvell/linux/sound/soc/pxa/mioa701_wm9713.c
new file mode 100644
index 0000000..129eb52
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/mioa701_wm9713.c
@@ -0,0 +1,201 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Handles the Mitac mioa701 SoC system
+ *
+ * Copyright (C) 2008 Robert Jarzmik
+ *
+ * This is a little schema of the sound interconnections :
+ *
+ *    Sagem X200                 Wolfson WM9713
+ *    +--------+             +-------------------+      Rear Speaker
+ *    |        |             |                   |           /-+
+ *    |        +--->----->---+MONOIN         SPKL+--->----+-+  |
+ *    |  GSM   |             |                   |        | |  |
+ *    |        +--->----->---+PCBEEP         SPKR+--->----+-+  |
+ *    |  CHIP  |             |                   |           \-+
+ *    |        +---<-----<---+MONO               |
+ *    |        |             |                   |      Front Speaker
+ *    +--------+             |                   |           /-+
+ *                           |                HPL+--->----+-+  |
+ *                           |                   |        | |  |
+ *                           |               OUT3+--->----+-+  |
+ *                           |                   |           \-+
+ *                           |                   |
+ *                           |                   |     Front Micro
+ *                           |                   |         +
+ *                           |               MIC1+-----<--+o+
+ *                           |                   |         +
+ *                           +-------------------+        ---
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/platform_device.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/initval.h>
+#include <sound/ac97_codec.h>
+
+#include "../codecs/wm9713.h"
+
+#define AC97_GPIO_PULL		0x58
+
+/* Use GPIO8 for rear speaker amplifier */
+static int rear_amp_power(struct snd_soc_component *component, int power)
+{
+	unsigned short reg;
+
+	if (power) {
+		reg = snd_soc_component_read32(component, AC97_GPIO_CFG);
+		snd_soc_component_write(component, AC97_GPIO_CFG, reg | 0x0100);
+		reg = snd_soc_component_read32(component, AC97_GPIO_PULL);
+		snd_soc_component_write(component, AC97_GPIO_PULL, reg | (1<<15));
+	} else {
+		reg = snd_soc_component_read32(component, AC97_GPIO_CFG);
+		snd_soc_component_write(component, AC97_GPIO_CFG, reg & ~0x0100);
+		reg = snd_soc_component_read32(component, AC97_GPIO_PULL);
+		snd_soc_component_write(component, AC97_GPIO_PULL, reg & ~(1<<15));
+	}
+
+	return 0;
+}
+
+static int rear_amp_event(struct snd_soc_dapm_widget *widget,
+			  struct snd_kcontrol *kctl, int event)
+{
+	struct snd_soc_card *card = widget->dapm->card;
+	struct snd_soc_pcm_runtime *rtd;
+	struct snd_soc_component *component;
+
+	rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name);
+	component = rtd->codec_dai->component;
+	return rear_amp_power(component, SND_SOC_DAPM_EVENT_ON(event));
+}
+
+/* mioa701 machine dapm widgets */
+static const struct snd_soc_dapm_widget mioa701_dapm_widgets[] = {
+	SND_SOC_DAPM_SPK("Front Speaker", NULL),
+	SND_SOC_DAPM_SPK("Rear Speaker", rear_amp_event),
+	SND_SOC_DAPM_MIC("Headset", NULL),
+	SND_SOC_DAPM_LINE("GSM Line Out", NULL),
+	SND_SOC_DAPM_LINE("GSM Line In", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Front Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* Call Mic */
+	{"Mic Bias", NULL, "Front Mic"},
+	{"MIC1", NULL, "Mic Bias"},
+
+	/* Headset Mic */
+	{"LINEL", NULL, "Headset Mic"},
+	{"LINER", NULL, "Headset Mic"},
+
+	/* GSM Module */
+	{"MONOIN", NULL, "GSM Line Out"},
+	{"PCBEEP", NULL, "GSM Line Out"},
+	{"GSM Line In", NULL, "MONO"},
+
+	/* headphone connected to HPL, HPR */
+	{"Headset", NULL, "HPL"},
+	{"Headset", NULL, "HPR"},
+
+	/* front speaker connected to HPL, OUT3 */
+	{"Front Speaker", NULL, "HPL"},
+	{"Front Speaker", NULL, "OUT3"},
+
+	/* rear speaker connected to SPKL, SPKR */
+	{"Rear Speaker", NULL, "SPKL"},
+	{"Rear Speaker", NULL, "SPKR"},
+};
+
+static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *component = rtd->codec_dai->component;
+
+	/* Prepare GPIO8 for rear speaker amplifier */
+	snd_soc_component_update_bits(component, AC97_GPIO_CFG, 0x100, 0x100);
+
+	/* Prepare MIC input */
+	snd_soc_component_update_bits(component, AC97_3D_CONTROL, 0xc000, 0xc000);
+
+	return 0;
+}
+
+static struct snd_soc_ops mioa701_ops;
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link mioa701_dai[] = {
+	{
+		.name = "AC97",
+		.stream_name = "AC97 HiFi",
+		.init = mioa701_wm9713_init,
+		.ops = &mioa701_ops,
+		SND_SOC_DAILINK_REG(ac97),
+	},
+	{
+		.name = "AC97 Aux",
+		.stream_name = "AC97 Aux",
+		.ops = &mioa701_ops,
+		SND_SOC_DAILINK_REG(ac97_aux),
+	},
+};
+
+static struct snd_soc_card mioa701 = {
+	.name = "MioA701",
+	.owner = THIS_MODULE,
+	.dai_link = mioa701_dai,
+	.num_links = ARRAY_SIZE(mioa701_dai),
+
+	.dapm_widgets = mioa701_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static int mioa701_wm9713_probe(struct platform_device *pdev)
+{
+	int rc;
+
+	if (!machine_is_mioa701())
+		return -ENODEV;
+
+	mioa701.dev = &pdev->dev;
+	rc = devm_snd_soc_register_card(&pdev->dev, &mioa701);
+	if (!rc)
+		dev_warn(&pdev->dev, "Be warned that incorrect mixers/muxes setup will "
+			 "lead to overheating and possible destruction of your device."
+			 " Do not use without a good knowledge of mio's board design!\n");
+	return rc;
+}
+
+static struct platform_driver mioa701_wm9713_driver = {
+	.probe		= mioa701_wm9713_probe,
+	.driver		= {
+		.name		= "mioa701-wm9713",
+		.pm     = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(mioa701_wm9713_driver);
+
+/* Module information */
+MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)");
+MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mioa701-wm9713");
diff --git a/marvell/linux/sound/soc/pxa/mmp-pcm.c b/marvell/linux/sound/soc/pxa/mmp-pcm.c
new file mode 100644
index 0000000..e9f9642
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/mmp-pcm.c
@@ -0,0 +1,250 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/sound/soc/pxa/mmp-pcm.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-mmp_tdma.h>
+#include <linux/platform_data/mmp_audio.h>
+
+#include <sound/pxa2xx-lib.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+
+#define DRV_NAME "mmp-pcm"
+
+struct mmp_dma_data {
+	int ssp_id;
+	struct resource *dma_res;
+};
+
+#define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP |	\
+		SNDRV_PCM_INFO_MMAP_VALID |	\
+		SNDRV_PCM_INFO_INTERLEAVED |	\
+		SNDRV_PCM_INFO_PAUSE |		\
+		SNDRV_PCM_INFO_RESUME |		\
+		SNDRV_PCM_INFO_NO_PERIOD_WAKEUP)
+
+static struct snd_pcm_hardware mmp_pcm_hardware[] = {
+	{
+		.info			= MMP_PCM_INFO,
+		.period_bytes_min	= 1024,
+		.period_bytes_max	= 2048,
+		.periods_min		= 2,
+		.periods_max		= 32,
+		.buffer_bytes_max	= 4096,
+		.fifo_size		= 32,
+	},
+	{
+		.info			= MMP_PCM_INFO,
+		.period_bytes_min	= 1024,
+		.period_bytes_max	= 2048,
+		.periods_min		= 2,
+		.periods_max		= 32,
+		.buffer_bytes_max	= 4096,
+		.fifo_size		= 32,
+	},
+};
+
+static int mmp_pcm_hw_params(struct snd_pcm_substream *substream,
+			      struct snd_pcm_hw_params *params)
+{
+	struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
+	struct dma_slave_config slave_config;
+	int ret;
+
+	ret =
+	    snd_dmaengine_pcm_prepare_slave_config(substream, params,
+						   &slave_config);
+	if (ret)
+		return ret;
+
+	ret = dmaengine_slave_config(chan, &slave_config);
+	if (ret)
+		return ret;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+
+	return 0;
+}
+
+static bool filter(struct dma_chan *chan, void *param)
+{
+	struct mmp_dma_data *dma_data = param;
+	bool found = false;
+	char *devname;
+
+	devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name,
+		dma_data->ssp_id);
+	if (devname && (strcmp(dev_name(chan->device->dev), devname) == 0) &&
+		(chan->chan_id == dma_data->dma_res->start)) {
+		found = true;
+	}
+
+	kfree(devname);
+	return found;
+}
+
+static int mmp_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_component *component = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+	struct platform_device *pdev = to_platform_device(component->dev);
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct mmp_dma_data dma_data;
+	struct resource *r;
+
+	r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
+	if (!r)
+		return -EBUSY;
+
+	snd_soc_set_runtime_hwparams(substream,
+				&mmp_pcm_hardware[substream->stream]);
+
+	dma_data.dma_res = r;
+	dma_data.ssp_id = cpu_dai->id;
+
+	return snd_dmaengine_pcm_open_request_chan(substream, filter,
+		    &dma_data);
+}
+
+static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
+			 struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	unsigned long off = vma->vm_pgoff;
+
+	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+	return remap_pfn_range(vma, vma->vm_start,
+		__phys_to_pfn(runtime->dma_addr) + off,
+		vma->vm_end - vma->vm_start, vma->vm_page_prot);
+}
+
+static const struct snd_pcm_ops mmp_pcm_ops = {
+	.open		= mmp_pcm_open,
+	.close		= snd_dmaengine_pcm_close_release_chan,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= mmp_pcm_hw_params,
+	.trigger	= snd_dmaengine_pcm_trigger,
+	.pointer	= snd_dmaengine_pcm_pointer,
+	.mmap		= mmp_pcm_mmap,
+};
+
+static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+	struct gen_pool *gpool;
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return;
+
+	for (stream = 0; stream < 2; stream++) {
+		size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
+
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+		gen_pool_free(gpool, (unsigned long)buf->area, size);
+		buf->area = NULL;
+	}
+
+}
+
+static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream,
+								int stream)
+{
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = mmp_pcm_hardware[stream].buffer_bytes_max;
+	struct gen_pool *gpool;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = substream->pcm->card->dev;
+	buf->private_data = NULL;
+
+	gpool = sram_get_gpool("asram");
+	if (!gpool)
+		return -ENOMEM;
+
+	buf->area = gen_pool_dma_alloc(gpool, size, &buf->addr);
+	if (!buf->area)
+		return -ENOMEM;
+	buf->bytes = size;
+	return 0;
+}
+
+static int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_pcm *pcm = rtd->pcm;
+	int ret = 0, stream;
+
+	for (stream = 0; stream < 2; stream++) {
+		substream = pcm->streams[stream].substream;
+
+		ret = mmp_pcm_preallocate_dma_buffer(substream,	stream);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+
+err:
+	mmp_pcm_free_dma_buffers(pcm);
+	return ret;
+}
+
+static const struct snd_soc_component_driver mmp_soc_component = {
+	.name		= DRV_NAME,
+	.ops		= &mmp_pcm_ops,
+	.pcm_new	= mmp_pcm_new,
+	.pcm_free	= mmp_pcm_free_dma_buffers,
+};
+
+static int mmp_pcm_probe(struct platform_device *pdev)
+{
+	struct mmp_audio_platdata *pdata = pdev->dev.platform_data;
+
+	if (pdata) {
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max =
+						pdata->buffer_max_playback;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max =
+						pdata->period_max_playback;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max =
+						pdata->buffer_max_capture;
+		mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max =
+						pdata->period_max_capture;
+	}
+	return devm_snd_soc_register_component(&pdev->dev, &mmp_soc_component,
+					       NULL, 0);
+}
+
+static struct platform_driver mmp_pcm_driver = {
+	.driver = {
+		.name = "mmp-pcm-audio",
+	},
+
+	.probe = mmp_pcm_probe,
+};
+
+module_platform_driver(mmp_pcm_driver);
+
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_DESCRIPTION("MMP Soc Audio DMA module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mmp-pcm-audio");
diff --git a/marvell/linux/sound/soc/pxa/mmp-sspa.c b/marvell/linux/sound/soc/pxa/mmp-sspa.c
new file mode 100644
index 0000000..e3e5425
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/mmp-sspa.c
@@ -0,0 +1,467 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/sound/soc/pxa/mmp-sspa.c
+ * Base on pxa2xx-ssp.c
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ */
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/io.h>
+#include <linux/dmaengine.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
+#include "mmp-sspa.h"
+
+/*
+ * SSPA audio private data
+ */
+struct sspa_priv {
+	struct ssp_device *sspa;
+	struct snd_dmaengine_dai_dma_data *dma_params;
+	struct clk *audio_clk;
+	struct clk *sysclk;
+	int dai_fmt;
+	int running_cnt;
+};
+
+static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val)
+{
+	__raw_writel(val, sspa->mmio_base + reg);
+}
+
+static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg)
+{
+	return __raw_readl(sspa->mmio_base + reg);
+}
+
+static void mmp_sspa_tx_enable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
+	sspa_sp |= SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+}
+
+static void mmp_sspa_tx_disable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP);
+	sspa_sp &= ~SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+}
+
+static void mmp_sspa_rx_enable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
+	sspa_sp |= SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+}
+
+static void mmp_sspa_rx_disable(struct ssp_device *sspa)
+{
+	unsigned int sspa_sp;
+
+	sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP);
+	sspa_sp &= ~SSPA_SP_S_EN;
+	sspa_sp |= SSPA_SP_WEN;
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+}
+
+static int mmp_sspa_startup(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+	clk_enable(priv->sysclk);
+	clk_enable(priv->sspa->clk);
+
+	return 0;
+}
+
+static void mmp_sspa_shutdown(struct snd_pcm_substream *substream,
+	struct snd_soc_dai *dai)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+	clk_disable(priv->sspa->clk);
+	clk_disable(priv->sysclk);
+
+}
+
+/*
+ * Set the SSP ports SYSCLK.
+ */
+static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+				    int clk_id, unsigned int freq, int dir)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret = 0;
+
+	switch (clk_id) {
+	case MMP_SSPA_CLK_AUDIO:
+		ret = clk_set_rate(priv->audio_clk, freq);
+		if (ret)
+			return ret;
+		break;
+	case MMP_SSPA_CLK_PLL:
+	case MMP_SSPA_CLK_VCXO:
+		/* not support yet */
+		return -EINVAL;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+				 int source, unsigned int freq_in,
+				 unsigned int freq_out)
+{
+	struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	int ret = 0;
+
+	switch (pll_id) {
+	case MMP_SYSCLK:
+		ret = clk_set_rate(priv->sysclk, freq_out);
+		if (ret)
+			return ret;
+		break;
+	case MMP_SSPA_CLK:
+		ret = clk_set_rate(priv->sspa->clk, freq_out);
+		if (ret)
+			return ret;
+		break;
+	default:
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+/*
+ * Set up the sspa dai format. The sspa port must be inactive
+ * before calling this function as the physical
+ * interface format is changed.
+ */
+static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+				 unsigned int fmt)
+{
+	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *sspa = sspa_priv->sspa;
+	u32 sspa_sp, sspa_ctrl;
+
+	/* check if we need to change anything at all */
+	if (sspa_priv->dai_fmt == fmt)
+		return 0;
+
+	/* we can only change the settings if the port is not in use */
+	if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) ||
+	    (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) {
+		dev_err(&sspa->pdev->dev,
+			"can't change hardware dai format: stream is in use\n");
+		return -EINVAL;
+	}
+
+	/* reset port settings */
+	sspa_sp   = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH;
+	sspa_ctrl = 0;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		sspa_sp |= SSPA_SP_MSL;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		sspa_sp |= SSPA_SP_FSP;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		sspa_sp |= SSPA_TXSP_FPER(63);
+		sspa_sp |= SSPA_SP_FWID(31);
+		sspa_ctrl |= SSPA_CTL_XDATDLY(1);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+
+	sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH);
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+	mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp);
+
+	/*
+	 * FIXME: hw issue, for the tx serial port,
+	 * can not config the master/slave mode;
+	 * so must clean this bit.
+	 * The master/slave mode has been set in the
+	 * rx port.
+	 */
+	sspa_sp &= ~SSPA_SP_MSL;
+	mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp);
+
+	mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
+	mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
+
+	/* Since we are configuring the timings for the format by hand
+	 * we have to defer some things until hw_params() where we
+	 * know parameters like the sample size.
+	 */
+	sspa_priv->dai_fmt = fmt;
+	return 0;
+}
+
+/*
+ * Set the SSPA audio DMA parameters and sample size.
+ * Can be called multiple times by oss emulation.
+ */
+static int mmp_sspa_hw_params(struct snd_pcm_substream *substream,
+			       struct snd_pcm_hw_params *params,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
+	struct ssp_device *sspa = sspa_priv->sspa;
+	struct snd_dmaengine_dai_dma_data *dma_params;
+	u32 sspa_ctrl;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL);
+	else
+		sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL);
+
+	sspa_ctrl &= ~SSPA_CTL_XFRLEN1_MASK;
+	sspa_ctrl |= SSPA_CTL_XFRLEN1(params_channels(params) - 1);
+	sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK;
+	sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS);
+	sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S8:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S16_LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S20_3LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S24_3LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl);
+		mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1);
+	} else {
+		mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl);
+		mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0);
+	}
+
+	dma_params = &sspa_priv->dma_params[substream->stream];
+	dma_params->addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+				(sspa->phys_base + SSPA_TXD) :
+				(sspa->phys_base + SSPA_RXD);
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params);
+	return 0;
+}
+
+static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd,
+			     struct snd_soc_dai *dai)
+{
+	struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai);
+	struct ssp_device *sspa = sspa_priv->sspa;
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		/*
+		 * whatever playback or capture, must enable rx.
+		 * this is a hw issue, so need check if rx has been
+		 * enabled or not; if has been enabled by another
+		 * stream, do not enable again.
+		 */
+		if (!sspa_priv->running_cnt)
+			mmp_sspa_rx_enable(sspa);
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			mmp_sspa_tx_enable(sspa);
+
+		sspa_priv->running_cnt++;
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		sspa_priv->running_cnt--;
+
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			mmp_sspa_tx_disable(sspa);
+
+		/* have no capture stream, disable rx port */
+		if (!sspa_priv->running_cnt)
+			mmp_sspa_rx_disable(sspa);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int mmp_sspa_probe(struct snd_soc_dai *dai)
+{
+	struct sspa_priv *priv = dev_get_drvdata(dai->dev);
+
+	snd_soc_dai_set_drvdata(dai, priv);
+	return 0;
+
+}
+
+#define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000
+#define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+		SNDRV_PCM_FMTBIT_S16_LE | \
+		SNDRV_PCM_FMTBIT_S24_LE | \
+		SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops mmp_sspa_dai_ops = {
+	.startup	= mmp_sspa_startup,
+	.shutdown	= mmp_sspa_shutdown,
+	.trigger	= mmp_sspa_trigger,
+	.hw_params	= mmp_sspa_hw_params,
+	.set_sysclk	= mmp_sspa_set_dai_sysclk,
+	.set_pll	= mmp_sspa_set_dai_pll,
+	.set_fmt	= mmp_sspa_set_dai_fmt,
+};
+
+static struct snd_soc_dai_driver mmp_sspa_dai = {
+	.probe = mmp_sspa_probe,
+	.playback = {
+		.channels_min = 1,
+		.channels_max = 128,
+		.rates = MMP_SSPA_RATES,
+		.formats = MMP_SSPA_FORMATS,
+	},
+	.capture = {
+		.channels_min = 1,
+		.channels_max = 2,
+		.rates = MMP_SSPA_RATES,
+		.formats = MMP_SSPA_FORMATS,
+	},
+	.ops = &mmp_sspa_dai_ops,
+};
+
+static const struct snd_soc_component_driver mmp_sspa_component = {
+	.name		= "mmp-sspa",
+};
+
+static int asoc_mmp_sspa_probe(struct platform_device *pdev)
+{
+	struct sspa_priv *priv;
+
+	priv = devm_kzalloc(&pdev->dev,
+				sizeof(struct sspa_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->sspa = devm_kzalloc(&pdev->dev,
+				sizeof(struct ssp_device), GFP_KERNEL);
+	if (priv->sspa == NULL)
+		return -ENOMEM;
+
+	priv->dma_params = devm_kcalloc(&pdev->dev,
+			2, sizeof(struct snd_dmaengine_dai_dma_data),
+			GFP_KERNEL);
+	if (priv->dma_params == NULL)
+		return -ENOMEM;
+
+	priv->sspa->mmio_base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->sspa->mmio_base))
+		return PTR_ERR(priv->sspa->mmio_base);
+
+	priv->sspa->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(priv->sspa->clk))
+		return PTR_ERR(priv->sspa->clk);
+
+	priv->audio_clk = clk_get(NULL, "mmp-audio");
+	if (IS_ERR(priv->audio_clk))
+		return PTR_ERR(priv->audio_clk);
+
+	priv->sysclk = clk_get(NULL, "mmp-sysclk");
+	if (IS_ERR(priv->sysclk)) {
+		clk_put(priv->audio_clk);
+		return PTR_ERR(priv->sysclk);
+	}
+	clk_enable(priv->audio_clk);
+	priv->dai_fmt = (unsigned int) -1;
+	platform_set_drvdata(pdev, priv);
+
+	return devm_snd_soc_register_component(&pdev->dev, &mmp_sspa_component,
+					       &mmp_sspa_dai, 1);
+}
+
+static int asoc_mmp_sspa_remove(struct platform_device *pdev)
+{
+	struct sspa_priv *priv = platform_get_drvdata(pdev);
+
+	clk_disable(priv->audio_clk);
+	clk_put(priv->audio_clk);
+	clk_put(priv->sysclk);
+	return 0;
+}
+
+static struct platform_driver asoc_mmp_sspa_driver = {
+	.driver = {
+		.name = "mmp-sspa-dai",
+	},
+	.probe = asoc_mmp_sspa_probe,
+	.remove = asoc_mmp_sspa_remove,
+};
+
+module_platform_driver(asoc_mmp_sspa_driver);
+
+MODULE_AUTHOR("Leo Yan <leoy@marvell.com>");
+MODULE_DESCRIPTION("MMP SSPA SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mmp-sspa-dai");
diff --git a/marvell/linux/sound/soc/pxa/mmp-sspa.h b/marvell/linux/sound/soc/pxa/mmp-sspa.h
new file mode 100644
index 0000000..7d1b7c7
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/mmp-sspa.h
@@ -0,0 +1,78 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * linux/sound/soc/pxa/mmp-sspa.h
+ *
+ * Copyright (C) 2011 Marvell International Ltd.
+ */
+#ifndef _MMP_SSPA_H
+#define _MMP_SSPA_H
+
+/*
+ * SSPA Registers
+ */
+#define SSPA_RXD		(0x00)
+#define SSPA_RXID		(0x04)
+#define SSPA_RXCTL		(0x08)
+#define SSPA_RXSP		(0x0c)
+#define SSPA_RXFIFO_UL		(0x10)
+#define SSPA_RXINT_MASK		(0x14)
+#define SSPA_RXC		(0x18)
+#define SSPA_RXFIFO_NOFS	(0x1c)
+#define SSPA_RXFIFO_SIZE	(0x20)
+
+#define SSPA_TXD		(0x80)
+#define SSPA_TXID		(0x84)
+#define SSPA_TXCTL		(0x88)
+#define SSPA_TXSP		(0x8c)
+#define SSPA_TXFIFO_LL		(0x90)
+#define SSPA_TXINT_MASK		(0x94)
+#define SSPA_TXC		(0x98)
+#define SSPA_TXFIFO_NOFS	(0x9c)
+#define SSPA_TXFIFO_SIZE	(0xa0)
+
+/* SSPA Control Register */
+#define	SSPA_CTL_XPH		(1 << 31)	/* Read Phase */
+#define	SSPA_CTL_XFIG		(1 << 15)	/* Transmit Zeros when FIFO Empty */
+#define	SSPA_CTL_JST		(1 << 3)	/* Audio Sample Justification */
+#define	SSPA_CTL_XFRLEN2_MASK	(7 << 24)
+#define	SSPA_CTL_XFRLEN2(x)	((x) << 24)	/* Transmit Frame Length in Phase 2 */
+#define	SSPA_CTL_XWDLEN2_MASK	(7 << 21)
+#define	SSPA_CTL_XWDLEN2(x)	((x) << 21)	/* Transmit Word Length in Phase 2 */
+#define	SSPA_CTL_XDATDLY(x)	((x) << 19)	/* Tansmit Data Delay */
+#define	SSPA_CTL_XSSZ2_MASK	(7 << 16)
+#define	SSPA_CTL_XSSZ2(x)	((x) << 16)	/* Transmit Sample Audio Size */
+#define	SSPA_CTL_XFRLEN1_MASK	(7 << 8)
+#define	SSPA_CTL_XFRLEN1(x)	((x) << 8)	/* Transmit Frame Length in Phase 1 */
+#define	SSPA_CTL_XWDLEN1_MASK	(7 << 5)
+#define	SSPA_CTL_XWDLEN1(x)	((x) << 5)	/* Transmit Word Length in Phase 1 */
+#define	SSPA_CTL_XSSZ1_MASK	(7 << 0)
+#define	SSPA_CTL_XSSZ1(x)	((x) << 0)	/* XSSZ1 */
+
+#define SSPA_CTL_8_BITS		(0x0)		/* Sample Size */
+#define SSPA_CTL_12_BITS	(0x1)
+#define SSPA_CTL_16_BITS	(0x2)
+#define SSPA_CTL_20_BITS	(0x3)
+#define SSPA_CTL_24_BITS	(0x4)
+#define SSPA_CTL_32_BITS	(0x5)
+
+/* SSPA Serial Port Register */
+#define	SSPA_SP_WEN		(1 << 31)	/* Write Configuration Enable */
+#define	SSPA_SP_MSL		(1 << 18)	/* Master Slave Configuration */
+#define	SSPA_SP_CLKP		(1 << 17)	/* CLKP Polarity Clock Edge Select */
+#define	SSPA_SP_FSP		(1 << 16)	/* FSP Polarity Clock Edge Select */
+#define	SSPA_SP_FFLUSH		(1 << 2)	/* FIFO Flush */
+#define	SSPA_SP_S_RST		(1 << 1)	/* Active High Reset Signal */
+#define	SSPA_SP_S_EN		(1 << 0)	/* Serial Clock Domain Enable */
+#define	SSPA_SP_FWID(x)		((x) << 20)	/* Frame-Sync Width */
+#define	SSPA_TXSP_FPER(x)	((x) << 4)	/* Frame-Sync Active */
+
+/* sspa clock sources */
+#define MMP_SSPA_CLK_PLL	0
+#define MMP_SSPA_CLK_VCXO	1
+#define MMP_SSPA_CLK_AUDIO	3
+
+/* sspa pll id */
+#define MMP_SYSCLK		0
+#define MMP_SSPA_CLK		1
+
+#endif /* _MMP_SSPA_H */
diff --git a/marvell/linux/sound/soc/pxa/palm27x.c b/marvell/linux/sound/soc/pxa/palm27x.c
new file mode 100644
index 0000000..b92ea1a
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/palm27x.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/sound/soc/pxa/palm27x.c
+ *
+ * SoC Audio driver for Palm T|X, T5 and LifeDrive
+ *
+ * based on tosa.c
+ *
+ * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+#include <mach/audio.h>
+#include <linux/platform_data/asoc-palm27x.h>
+
+static struct snd_soc_jack hs_jack;
+
+/* Headphones jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+	{
+		.pin    = "Headphone Jack",
+		.mask   = SND_JACK_HEADPHONE,
+	},
+};
+
+/* Headphones jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+	[0] = {
+		/* gpio is set on per-platform basis */
+		.name           = "hp-gpio",
+		.report         = SND_JACK_HEADPHONE,
+		.debounce_time	= 200,
+	},
+};
+
+/* Palm27x machine dapm widgets */
+static const struct snd_soc_dapm_widget palm27x_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_SPK("Ext. Speaker", NULL),
+	SND_SOC_DAPM_MIC("Ext. Microphone", NULL),
+};
+
+/* PalmTX audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+	/* headphone connected to HPOUTL, HPOUTR */
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Headphone Jack", NULL, "HPOUTR"},
+
+	/* ext speaker connected to ROUT2, LOUT2 */
+	{"Ext. Speaker", NULL, "LOUT2"},
+	{"Ext. Speaker", NULL, "ROUT2"},
+
+	/* mic connected to MIC1 */
+	{"MIC1", NULL, "Ext. Microphone"},
+};
+
+static struct snd_soc_card palm27x_asoc;
+
+static int palm27x_ac97_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int err;
+
+	/* Jack detection API stuff */
+	err = snd_soc_card_jack_new(rtd->card, "Headphone Jack",
+				    SND_JACK_HEADPHONE, &hs_jack, hs_jack_pins,
+				    ARRAY_SIZE(hs_jack_pins));
+	if (err)
+		return err;
+
+	err = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+				hs_jack_gpios);
+
+	return err;
+}
+
+SND_SOC_DAILINK_DEFS(hifi,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link palm27x_dai[] = {
+{
+	.name = "AC97 HiFi",
+	.stream_name = "AC97 HiFi",
+	.init = palm27x_ac97_init,
+	SND_SOC_DAILINK_REG(hifi),
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	SND_SOC_DAILINK_REG(aux),
+},
+};
+
+static struct snd_soc_card palm27x_asoc = {
+	.name = "Palm/PXA27x",
+	.owner = THIS_MODULE,
+	.dai_link = palm27x_dai,
+	.num_links = ARRAY_SIZE(palm27x_dai),
+	.dapm_widgets = palm27x_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(palm27x_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.fully_routed = true,
+};
+
+static int palm27x_asoc_probe(struct platform_device *pdev)
+{
+	int ret;
+
+	if (!(machine_is_palmtx() || machine_is_palmt5() ||
+		machine_is_palmld() || machine_is_palmte2()))
+		return -ENODEV;
+
+	if (!pdev->dev.platform_data) {
+		dev_err(&pdev->dev, "please supply platform_data\n");
+		return -ENODEV;
+	}
+
+	hs_jack_gpios[0].gpio = ((struct palm27x_asoc_info *)
+			(pdev->dev.platform_data))->jack_gpio;
+
+	palm27x_asoc.dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, &palm27x_asoc);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+	return ret;
+}
+
+static struct platform_driver palm27x_wm9712_driver = {
+	.probe		= palm27x_asoc_probe,
+	.driver		= {
+		.name		= "palm27x-asoc",
+		.pm     = &snd_soc_pm_ops,
+	},
+};
+
+module_platform_driver(palm27x_wm9712_driver);
+
+/* Module information */
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:palm27x-asoc");
diff --git a/marvell/linux/sound/soc/pxa/poodle.c b/marvell/linux/sound/soc/pxa/poodle.c
new file mode 100644
index 0000000..48d5c22
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/poodle.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * poodle.c  --  SoC audio for Poodle
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *          Richard Purdie <richard@openedhand.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <asm/hardware/locomo.h>
+#include <mach/poodle.h>
+#include <mach/audio.h>
+
+#include "../codecs/wm8731.h"
+#include "pxa2xx-i2s.h"
+
+#define POODLE_HP        1
+#define POODLE_HP_OFF    0
+#define POODLE_SPK_ON    1
+#define POODLE_SPK_OFF   0
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define POODLE_AUDIO_CLOCK 12288000
+
+static int poodle_jack_func;
+static int poodle_spk_func;
+
+static void poodle_ext_control(struct snd_soc_dapm_context *dapm)
+{
+	/* set up jack connection */
+	if (poodle_jack_func == POODLE_HP) {
+		/* set = unmute headphone */
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_L, 1);
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_R, 1);
+		snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
+	} else {
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_L, 0);
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_MUTE_R, 0);
+		snd_soc_dapm_disable_pin(dapm, "Headphone Jack");
+	}
+
+	/* set the enpoints to their new connetion states */
+	if (poodle_spk_func == POODLE_SPK_ON)
+		snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+	else
+		snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+
+	/* signal a DAPM event */
+	snd_soc_dapm_sync(dapm);
+}
+
+static int poodle_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* check the jack status at stream startup */
+	poodle_ext_control(&rtd->card->dapm);
+
+	return 0;
+}
+
+/* we need to unmute the HP at shutdown as the mute burns power on poodle */
+static void poodle_shutdown(struct snd_pcm_substream *substream)
+{
+	/* set = unmute headphone */
+	locomo_gpio_write(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_L, 1);
+	locomo_gpio_write(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_R, 1);
+}
+
+static int poodle_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8731_SYSCLK_XTAL, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_ops poodle_ops = {
+	.startup = poodle_startup,
+	.hw_params = poodle_hw_params,
+	.shutdown = poodle_shutdown,
+};
+
+static int poodle_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = poodle_jack_func;
+	return 0;
+}
+
+static int poodle_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
+
+	if (poodle_jack_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	poodle_jack_func = ucontrol->value.enumerated.item[0];
+	poodle_ext_control(&card->dapm);
+	return 1;
+}
+
+static int poodle_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = poodle_spk_func;
+	return 0;
+}
+
+static int poodle_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card =  snd_kcontrol_chip(kcontrol);
+
+	if (poodle_spk_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	poodle_spk_func = ucontrol->value.enumerated.item[0];
+	poodle_ext_control(&card->dapm);
+	return 1;
+}
+
+static int poodle_amp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	if (SND_SOC_DAPM_EVENT_ON(event))
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_AMP_ON, 0);
+	else
+		locomo_gpio_write(&poodle_locomo_device.dev,
+			POODLE_LOCOMO_GPIO_AMP_ON, 1);
+
+	return 0;
+}
+
+/* poodle machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", NULL),
+SND_SOC_DAPM_SPK("Ext Spk", poodle_amp_event),
+SND_SOC_DAPM_MIC("Microphone", NULL),
+};
+
+/* Corgi machine connections to the codec pins */
+static const struct snd_soc_dapm_route poodle_audio_map[] = {
+
+	/* headphone connected to LHPOUT1, RHPOUT1 */
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	/* speaker connected to LOUT, ROUT */
+	{"Ext Spk", NULL, "ROUT"},
+	{"Ext Spk", NULL, "LOUT"},
+
+	{"MICIN", NULL, "Microphone"},
+};
+
+static const char * const jack_function[] = {"Off", "Headphone"};
+static const char * const spk_function[] = {"Off", "On"};
+static const struct soc_enum poodle_enum[] = {
+	SOC_ENUM_SINGLE_EXT(2, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8731_poodle_controls[] = {
+	SOC_ENUM_EXT("Jack Function", poodle_enum[0], poodle_get_jack,
+		poodle_set_jack),
+	SOC_ENUM_EXT("Speaker Function", poodle_enum[1], poodle_get_spk,
+		poodle_set_spk),
+};
+
+/* poodle digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(wm8731,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm8731.0-001b", "wm8731-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link poodle_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+	.ops = &poodle_ops,
+	SND_SOC_DAILINK_REG(wm8731),
+};
+
+/* poodle audio machine driver */
+static struct snd_soc_card poodle = {
+	.name = "Poodle",
+	.dai_link = &poodle_dai,
+	.num_links = 1,
+	.owner = THIS_MODULE,
+
+	.controls = wm8731_poodle_controls,
+	.num_controls = ARRAY_SIZE(wm8731_poodle_controls),
+	.dapm_widgets = wm8731_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
+	.dapm_routes = poodle_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(poodle_audio_map),
+	.fully_routed = true,
+};
+
+static int poodle_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &poodle;
+	int ret;
+
+	locomo_gpio_set_dir(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_AMP_ON, 0);
+	/* should we mute HP at startup - burning power ?*/
+	locomo_gpio_set_dir(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_L, 0);
+	locomo_gpio_set_dir(&poodle_locomo_device.dev,
+		POODLE_LOCOMO_GPIO_MUTE_R, 0);
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+	return ret;
+}
+
+static struct platform_driver poodle_driver = {
+	.driver		= {
+		.name	= "poodle-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= poodle_probe,
+};
+
+module_platform_driver(poodle_driver);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Poodle");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:poodle-audio");
diff --git a/marvell/linux/sound/soc/pxa/pxa-alc5616.c b/marvell/linux/sound/soc/pxa/pxa-alc5616.c
new file mode 100644
index 0000000..b194ae2
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa-alc5616.c
@@ -0,0 +1,148 @@
+/*
+ * linux/sound/soc/pxa/pxa-alc5616.c
+ *
+ * Copyright (C) 2013 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm8xxx-headset.h>
+#include <linux/features.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <sound/pcm_params.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/input.h>
+#include "pxa-ssp.h"
+
+#ifdef CONFIG_SND_PXA_SSP_DUMP
+int ssp_playback_enable;
+int ssp_capture_enable;
+int gssp_playback_enable;
+int gssp_capture_enable;
+#endif
+
+//extern void enable_5616_MClock(void);
+extern void codec_rt5616_Enable_Headsetdetection(void);
+
+static int pxa_alc5616_hifi_startup(struct snd_pcm_substream *substream)
+{
+    return 0;
+}
+
+static int pxa_alc5616_hw_params(struct snd_pcm_substream *substream,
+        struct snd_pcm_hw_params *params)
+{
+    return 0;
+}
+
+static int pxa_alc5616_hifi_prepare(struct snd_pcm_substream *substream)
+{
+    return 0;
+}
+
+static int pxa_alc5616_late_probe(struct snd_soc_card *card)
+{
+    //enable_5616_MClock();
+    //codec_rt5616_Enable_Headsetdetection();
+    printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
+
+    return 0;
+}
+
+static const struct snd_soc_ops pxa_alc5616_machine_ops[] = {
+    {
+        .startup = pxa_alc5616_hifi_startup,
+        .hw_params = pxa_alc5616_hw_params,
+        .prepare = pxa_alc5616_hifi_prepare,
+    },
+};
+
+#ifdef CONFIG_CPU_ASR1901
+SND_SOC_DAILINK_DEFS(alc5616,
+    DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.1")),
+    DAILINK_COMP_ARRAY(COMP_CODEC("alc5616.1-001b", "alc5616-pcm")),
+    DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-ssp-dai.1")));
+#else
+SND_SOC_DAILINK_DEFS(alc5616,
+    DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.1")),
+    DAILINK_COMP_ARRAY(COMP_CODEC("alc5616.0-001b", "alc5616-pcm")),
+    DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-ssp-dai.1")));
+#endif
+
+static struct snd_soc_dai_link pxa_alc5616_dai[] = {
+    {
+        .name = "alc5616 pcm",
+        .stream_name = "mrvl-ssp",
+        .ops = &pxa_alc5616_machine_ops[0],
+        SND_SOC_DAILINK_REG(alc5616),
+    },
+};
+
+static struct snd_soc_card pxa_alc5616_card = {
+    .name = "pxa-alc5616-dkb-voice",
+    .dai_link = pxa_alc5616_dai,
+    .num_links = ARRAY_SIZE(pxa_alc5616_dai),
+    .late_probe = pxa_alc5616_late_probe,
+};
+
+static struct of_device_id pxa_alc5616_dt_ids[] = {
+    { .compatible = "ASRMICRO,asrmicro-snd-card", },
+    {}
+};
+MODULE_DEVICE_TABLE(of, pxa_alc5616_dt_ids);
+
+static int pxa_alc5616_probe(struct platform_device *pdev)
+{
+    int ret;
+    struct snd_soc_card *card = &pxa_alc5616_card;
+
+    pr_pm_debug(KERN_INFO"[5616 card probe: begin] %s/L%d.\n", __FUNCTION__, __LINE__);
+
+    card->dev = &pdev->dev;
+
+    ret = devm_snd_soc_register_card(&pdev->dev, card);
+    //if (ret)
+        //dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", ret);
+
+    pr_pm_debug(KERN_INFO"[5616 card probe: end] %s/L%d.\n", __FUNCTION__, __LINE__);
+
+    return ret;
+}
+
+static struct platform_driver pxa_alc5616_driver = {
+    .driver		= {
+        .name	= "pxa-alc5616-platform",
+        .of_match_table = pxa_alc5616_dt_ids,
+        .pm     = &snd_soc_pm_ops,
+    },
+    .probe	= pxa_alc5616_probe,
+};
+
+module_platform_driver(pxa_alc5616_driver);
+
+/* Module information */
+MODULE_AUTHOR("wenchen@asrmicro.com");
+MODULE_DESCRIPTION("ALSA SoC TTC DKB");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa-alc5616-dkb-voice");
diff --git a/marvell/linux/sound/soc/pxa/pxa-nau8810.c b/marvell/linux/sound/soc/pxa/pxa-nau8810.c
new file mode 100644
index 0000000..3568d99
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa-nau8810.c
@@ -0,0 +1,168 @@
+/*
+ * linux/sound/soc/pxa/pxa-nau8810.c
+ *
+ * Copyright (C) 2013 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm8xxx-headset.h>
+#include <linux/features.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <sound/pcm_params.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/input.h>
+#include "pxa-ssp.h"
+
+#ifdef CONFIG_SND_PXA_SSP_DUMP
+int ssp_playback_enable;
+int ssp_capture_enable;
+int gssp_playback_enable;
+int gssp_capture_enable;
+#endif
+
+#ifndef CONFIG_CPU_ASR18XX
+u32 sscr0_hifi;
+u32 sscr1_hifi;
+#else
+u32 top_ctrl_hifi;
+u32 fifo_ctrl_hifi;
+u32 rwot_ctrl_hifi;
+u32 network_ctrl_hifi;
+u32 int_en_hifi;
+#endif
+
+static int pxa_nau8810_hifi_startup(struct snd_pcm_substream *substream)
+{
+    return 0;
+}
+
+static int pxa_nau8810_hw_params(struct snd_pcm_substream *substream,
+        struct snd_pcm_hw_params *params)
+{
+    return 0;
+}
+
+static int pxa_nau8810_hifi_prepare(struct snd_pcm_substream *substream)
+{
+    return 0;
+}
+
+static int pxa_nau8810_late_probe(struct snd_soc_card *card)
+{
+    return 0;
+}
+
+static struct snd_soc_ops pxa_nau8810_machine_ops[] = {
+    {
+        .startup = pxa_nau8810_hifi_startup,
+        .hw_params = pxa_nau8810_hw_params,
+        .prepare = pxa_nau8810_hifi_prepare,
+    },
+};
+
+#if 1
+SND_SOC_DAILINK_DEFS(nau8810,
+    DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.1")),
+    DAILINK_COMP_ARRAY(COMP_CODEC("nau8810.1-001a", "nau8810-pcm")),
+    DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-ssp-dai.1")));
+
+static struct snd_soc_dai_link pxa_nau8810_dai[] = {
+    {
+        .name = "nau8810 pcm",
+        .stream_name = "mrvl-ssp",
+        .ops = &pxa_nau8810_machine_ops[0],
+        SND_SOC_DAILINK_REG(nau8810),
+    },
+};
+#else
+static struct snd_soc_dai_link pxa_nau8810_dai[] = {
+    {
+        .name = "nau8810 pcm",
+        .stream_name = "mrvl-ssp",
+        .codec_name = "nau8810.1-001a",
+        .platform_name = "pxa-ssp-dai.1",
+        .cpu_dai_name = "pxa-ssp-dai.1",
+        .codec_dai_name = "nau8810-pcm",
+        .ops = &pxa_nau8810_machine_ops[0],
+    },
+};
+#endif
+
+static struct snd_soc_card pxa_nau8810_card = {
+    .name = "pxa-nau8810-dkb-voice",
+    .dai_link = pxa_nau8810_dai,
+    .num_links = ARRAY_SIZE(pxa_nau8810_dai),
+    .late_probe = pxa_nau8810_late_probe,
+};
+
+static struct of_device_id pxa_nau8810_dt_ids[] = {
+    { .compatible = "ASRMICRO,asrmicro-snd-card", },
+    {}
+};
+MODULE_DEVICE_TABLE(of, pxa_nau8810_dt_ids);
+
+static int pxa_nau8810_probe(struct platform_device *pdev)
+{
+    int ret;
+    struct snd_soc_card *card = &pxa_nau8810_card;
+
+    card->dev = &pdev->dev;
+
+    ret = snd_soc_register_card(card);
+    if (ret)
+        dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+                ret);
+
+    printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
+
+    return ret;
+}
+
+static int pxa_nau8810_remove(struct platform_device *pdev)
+{
+    struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+    snd_soc_unregister_card(card);
+
+    return 0;
+}
+
+static struct platform_driver pxa_nau8810_driver = {
+    .driver		= {
+        .name	= "pxa-nau8810-platform",
+        .owner	= THIS_MODULE,
+        .of_match_table = pxa_nau8810_dt_ids,
+    },
+    .probe	= pxa_nau8810_probe,
+    .remove	= pxa_nau8810_remove,
+};
+
+module_platform_driver(pxa_nau8810_driver);
+
+/* Module information */
+MODULE_AUTHOR("wenchen@asrmicro.com");
+MODULE_DESCRIPTION("ALSA SoC TTC DKB");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa-nau8810-dkb-voice");
diff --git a/marvell/linux/sound/soc/pxa/pxa-pcm.c b/marvell/linux/sound/soc/pxa/pxa-pcm.c
new file mode 100644
index 0000000..c9bd854
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa-pcm.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/dma/pxa-dma.h>
+
+static const struct snd_pcm_hardware pxa_pcm_hardware = {
+	.info			= SNDRV_PCM_INFO_MMAP |
+				  SNDRV_PCM_INFO_MMAP_VALID |
+				  SNDRV_PCM_INFO_INTERLEAVED |
+				  SNDRV_PCM_INFO_PAUSE |
+				  SNDRV_PCM_INFO_RESUME,
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
+				  SNDRV_PCM_FMTBIT_S24_LE |
+				  SNDRV_PCM_FMTBIT_S32_LE,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 8192 - 32,
+	.periods_min		= 1,
+	.periods_max		= 256, //PAGE_SIZE/sizeof(pxa_dma_desc),
+	.buffer_bytes_max	= 128 * 1024,
+	.fifo_size		= 32,
+};
+
+static const struct snd_dmaengine_pcm_config pxa_dmaengine_pcm_config = {
+	.pcm_hardware = &pxa_pcm_hardware,
+	.prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
+	.prealloc_buffer_size = 128 * 1024,
+};
+
+int pxa_pcm_platform_register(struct device *dev)
+{
+	return snd_dmaengine_pcm_register(dev, &pxa_dmaengine_pcm_config, 0);
+}
+EXPORT_SYMBOL_GPL(pxa_pcm_platform_register);
+
+void pxa_pcm_platform_unregister(struct device *dev)
+{
+	snd_dmaengine_pcm_unregister(dev);
+}
+EXPORT_SYMBOL_GPL(pxa_pcm_platform_unregister);
+
+MODULE_LICENSE("GPL");
diff --git a/marvell/linux/sound/soc/pxa/pxa-sndcard.c b/marvell/linux/sound/soc/pxa/pxa-sndcard.c
new file mode 100644
index 0000000..9a3d2eb
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa-sndcard.c
@@ -0,0 +1,977 @@
+/*
+ * linux/sound/soc/pxa/pxa-sndcard.c
+ *
+ * Copyright (C) 2013 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/88pm8xxx-headset.h>
+#include <linux/features.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <sound/pcm_params.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/input.h>
+#include "pxa-ssp.h"
+
+#ifdef CONFIG_SND_PXA_SSP_DUMP
+int ssp_playback_enable;
+int ssp_capture_enable;
+int gssp_playback_enable;
+int gssp_capture_enable;
+#endif
+
+static int gssp_master = 1;
+
+/* CODEC I2S config is Master in config/defconfig_asr1802sp201 */
+#ifdef CONFIG_CODEC_I2S_SLAVE
+
+/* CODEC is Slave, SSP is Master. */
+static int ssp_master = 1;
+
+#else
+
+/* CODEC is Master, SSP is slave. */
+static int ssp_master = 0; //0: PXA SSP as slave, hardware codec as master
+
+#endif
+
+
+u32 top_ctrl_hifi;
+u32 fifo_ctrl_hifi;
+u32 rwot_ctrl_hifi;
+u32 network_ctrl_hifi;
+u32 int_en_hifi;
+
+/* format for ASR1802SL */
+unsigned int channels;
+unsigned int rate;
+unsigned int sample_bits;
+unsigned int frame_bits;
+
+/*
+ * SSP audio private data
+ */
+struct ssp_priv {
+	struct ssp_device *ssp;
+	unsigned int sysclk;
+	int dai_fmt;
+#ifdef CONFIG_PM
+	uint32_t	cr0;
+	uint32_t	cr1;
+	uint32_t	to;
+	uint32_t	psp;
+#endif
+};
+
+extern int get_frame_bits(void);
+extern int get_status_switch_frame_bits(void);
+extern int get_status_IFS(void);
+extern int get_status_SFRMP(void);
+extern int get_status_SCMODE(void);
+extern u32 get_reg_value_from_UI(int offset);
+extern int get_status_debug_tools(void);
+
+int get_ssp_role(void)
+{
+    return ssp_master;
+}
+
+void set_ssp_role(int role)
+{
+    ssp_master = role;
+    printk(KERN_INFO"%s: SSP1 role is %s.\n", __FUNCTION__, ssp_master?"Master":"Slave");
+    return;
+}
+
+static ssize_t ssp_master_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%s\n", ssp_master?"SSP is Master!":"SSP is Slave!");
+}
+
+static ssize_t ssp_master_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	int ret;
+
+	ret = kstrtoint(buf, 10, &ssp_master);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(ssp_master, 0644, ssp_master_show, ssp_master_set);
+
+static ssize_t gssp_master_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", gssp_master);
+}
+
+static ssize_t gssp_master_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	int ret;
+
+	ret = kstrtoint(buf, 10, &gssp_master);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static DEVICE_ATTR(gssp_master, 0644, gssp_master_show, gssp_master_set);
+
+static ssize_t gssp_record_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", has_feat_hifi_gssp_record());
+}
+
+static DEVICE_ATTR(gssp_record, 0444, gssp_record_show, NULL);
+
+#ifdef CONFIG_SND_PXA_SSP_DUMP
+static DEVICE_INT_ATTR(ssp_playback_dump, 0644, ssp_playback_enable);
+static DEVICE_INT_ATTR(ssp_capture_dump, 0644, ssp_capture_enable);
+static DEVICE_INT_ATTR(gssp_playback_dump, 0644, gssp_playback_enable);
+static DEVICE_INT_ATTR(gssp_capture_dump, 0644, gssp_capture_enable);
+#endif
+
+static int pxa_sndcard_hifi_startup(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+static int pxa_sndcard_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	channels = params_channels(params);
+	rate = params_rate(params);
+	sample_bits = snd_pcm_format_physical_width(params_format(params));
+	frame_bits = sample_bits * channels;
+
+	if (get_status_switch_frame_bits())
+	{
+		/* for debug */
+		frame_bits = get_frame_bits();
+	} else {
+		/* get frame length from file format */
+		frame_bits = sample_bits * channels;
+	}
+
+	if (ssp_master)
+	{
+		snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+				SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+		snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+				SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+    }
+	else
+	{
+		snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+				SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+		snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+				SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
+	}
+	/*mclk is input clock of codec, it depends on codec configuration
+	*transfered by callback function
+	*/
+	snd_soc_dai_set_sysclk(codec_dai, 1, rate, SND_SOC_CLOCK_IN);
+	return 0;
+}
+extern void ssp_dump_registers(struct ssp_device *ssp);
+extern struct ssp_device *g_ssp;
+
+static int pxa_sndcard_hifi_prepare(struct snd_pcm_substream *substream)
+{
+    struct snd_soc_pcm_runtime *rtd = substream->private_data;
+    struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+    struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+    struct ssp_device *ssp = priv->ssp;
+
+    u32 top_ctrl, fifo_ctrl, rwot_ctrl, network_ctrl, psp_ctrl, int_en;
+    int scmode, status_debug_tool;
+
+    if (has_feat_hifi_gssp_record()) {
+
+        if(ssp_master) {
+            /* master mmode, drive SCLK and SFRM */
+            top_ctrl_hifi = top_ctrl_hifi & (~0x18);
+            /* Transmit/Receive service request enable
+             * TXFIFO/RXFIFO threshold as 0x8
+             */
+            fifo_ctrl_hifi = fifo_ctrl_hifi | 0xCE7;  //RX_AUTO_FULL_CTRL_EN       (0x1<<17)???
+            /* Receive without transmit */
+            //rwot_ctrl_hifi = rwot_ctrl_hifi | 0x1;
+        } else {
+            /* slave mmode, receive SCLK and SFRM */
+            top_ctrl_hifi = top_ctrl_hifi | 0x18;
+            /* Transmit/Receive service request enable
+             * TXFIFO/RXFIFO threshold as 0x8
+             */
+            fifo_ctrl_hifi = fifo_ctrl_hifi | 0xCE7;  //RX_AUTO_FULL_CTRL_EN       (0x1<<17)???
+            /* Receive without transmit */
+            //rwot_ctrl_hifi = rwot_ctrl_hifi | 0x1;
+        }
+
+        /* Frame Rate Divider Ctrl */
+        network_ctrl_hifi = network_ctrl_hifi | (1 << 1);
+        /* TIM/RIM */
+        int_en_hifi = int_en_hifi | (0x3 << 4);
+        /* 32bit data, Frame format as PSP */
+        top_ctrl_hifi = top_ctrl_hifi | (0x1f << 5) | (0x3 << 1);
+        __raw_writel(top_ctrl_hifi, ssp->mmio_base + TOP_CTRL);
+        __raw_writel(fifo_ctrl_hifi, ssp->mmio_base + FIFO_CTRL);
+        __raw_writel(rwot_ctrl_hifi, ssp->mmio_base + RWOT_CTRL); 
+        __raw_writel(int_en_hifi, ssp->mmio_base + INT_EN);
+        __raw_writel(network_ctrl_hifi, ssp->mmio_base + NET_WORK_CTRL);
+        __raw_writel(0x00010018, ssp->mmio_base + PSP_CTRL);
+
+    } else {
+
+        top_ctrl = __raw_readl(ssp->mmio_base + TOP_CTRL);
+        fifo_ctrl = __raw_readl(ssp->mmio_base + FIFO_CTRL);
+        rwot_ctrl = __raw_readl(ssp->mmio_base + RWOT_CTRL); 
+        int_en = __raw_readl(ssp->mmio_base + INT_EN);
+        network_ctrl = __raw_readl(ssp->mmio_base + NET_WORK_CTRL);
+
+        if(ssp_master){
+            /* ssp is Master */
+#if 1
+            //deleted for debug
+            top_ctrl = 0;
+            fifo_ctrl = 0;
+            int_en = 0;
+            psp_ctrl = 0;
+            network_ctrl = 0;
+            scmode = get_status_SCMODE();
+            status_debug_tool = get_status_debug_tools();
+            //rwot_ctrl = 0;
+
+            //Register:TOP_CTRL[0x00]
+            /* TXD Three-State Enable */
+            top_ctrl = top_ctrl | (0x1 << 17);
+
+            /*
+             *One:adjust polarity between codec bit[3:0] of register[0x32] in acm_pm805.h and ssp here
+             *IFS: bit15[TOP_CTRL]
+             */
+            if (get_status_IFS()) {
+                top_ctrl = top_ctrl | (0x01 << 15);
+            } else {
+                top_ctrl &= ~(0x01 << 15);
+            }
+
+            /* TRAIL:bit13 DMA bursts */
+            top_ctrl = top_ctrl | (0x1 << 13);
+
+            if (64 == frame_bits) {
+                /* 32bit data size, Frame format as PSP */
+                top_ctrl = top_ctrl | (0x1f << 5);
+            } else if (32 == frame_bits) {
+                /* 32bit data size, Frame format as PSP */
+                top_ctrl = top_ctrl | (0x1f << 5);
+            } else if (16 == frame_bits) {
+                /* 16bit data size, Frame format as PSP */
+                top_ctrl = top_ctrl | (0x0f << 5);
+            }
+
+            /* slave mode, receive SCLK and SFRM */
+            //top_ctrl = top_ctrl | (0x3 << 3);
+            /* master mode, receive SCLK and SFRM */
+            top_ctrl &= ~(0x3 << 3);
+
+            /* Frame format as PSP */
+            top_ctrl = top_ctrl | (0x3 << 1);
+
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(TOP_CTRL), ssp->mmio_base + TOP_CTRL);
+            } else {
+                __raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+            }
+#if 1
+            /*
+             *Register:FIFO_CTRL[0x04]
+             *Transmit/Receive service request enable
+             *TXFIFO/RXFIFO threshold as 0x8
+             *to avoid interrupt triggering
+             *when ssp configured for transporting 48kHz data
+             */
+
+            //fifo_ctrl = fifo_ctrl | (0x1 << 16);
+            fifo_ctrl = fifo_ctrl | (0x3 << 10);
+
+            /*RX FIFO Trigger Threshold*/
+            fifo_ctrl = fifo_ctrl | (0x7 << 5);
+
+            /*TX FIFO Trigger Threshold*/
+            fifo_ctrl = fifo_ctrl | (0x7 << 0);
+
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(FIFO_CTRL), ssp->mmio_base + FIFO_CTRL);
+            } else {
+                __raw_writel(fifo_ctrl, ssp->mmio_base + FIFO_CTRL);
+            }
+#else
+            /* test2 */
+            fifo_ctrl = fifo_ctrl | (0x1 << 17); /* RX_AUTO_FULL_CTRL_EN */
+            fifo_ctrl &= ~(0x1 << 16);/* FIFO_UNPACKING  */
+            fifo_ctrl = fifo_ctrl | (0x1 << 11);/* RX_REQ_EN */
+            fifo_ctrl = fifo_ctrl | (0x1 << 10);/* TX_REQ_EN */
+            fifo_ctrl = fifo_ctrl | (0x7 << 5);/* RX_THRES_7 */
+            fifo_ctrl = fifo_ctrl | (0x7 << 0);/* TX_THRES_7 */
+            __raw_writel(fifo_ctrl, ssp->mmio_base + FIFO_CTRL);
+#endif
+
+#if 0
+            __raw_writel(int_en, ssp->mmio_base + INT_EN);
+#else
+            /* test3 */
+            //int_en = int_en | (0x1 << 3);/* TX_FIFO_INT_EN */
+            //int_en = int_en | (0x1 << 2);/* RX_FIFO_INT_EN */
+            int_en = int_en | (0x1 << 1);/* TIMEOUT_EN */
+            int_en = int_en | (0x1 << 0);/* PERI_TRAIL_EN */
+
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(INT_EN), ssp->mmio_base + INT_EN);
+            } else {
+                __raw_writel(int_en, ssp->mmio_base + INT_EN);
+            }
+#endif
+
+#if 0
+            __raw_writel(0, ssp->mmio_base + TO);
+#else
+            /* test4
+            * set no timeout interrupt here
+            * the interrupt is triggered, which depends on the frequency of the sample rate
+            * If the sample rate is 8KHz, the interrupt is triggered too fast and there is no
+            * interrupt handler to deal with it.
+            */
+            __raw_writel(0x0, ssp->mmio_base + TO);
+#endif
+
+            if (64 == frame_bits) {
+                /* Serial Frame Width:32, SFRMWDTH */
+                psp_ctrl = psp_ctrl | (0x20 << 12);
+            } else if (32 == frame_bits) {
+                /* Register:PSP_CTRL[0x18] */
+                /* SFRMWDTH:must be needed when slave */
+                /* Serial Frame Width:16, SFRMWDTH */
+                psp_ctrl = psp_ctrl | (0x10 << 12);
+            } else if (16 == frame_bits) {
+                /* Serial Frame Width:8, SFRMWDTH */
+                psp_ctrl = psp_ctrl | (0x08 << 12);
+            }
+
+            /*
+             *Two:adjust polarity between codec bit[3:0] of register[0x32] in acm_pm805.h and ssp here
+             *Frame Polarity bit[4]
+             */
+            /* SFRMP */
+            //psp_ctrl = psp_ctrl | (0x1 << 4);
+            if (get_status_SFRMP()) {
+                psp_ctrl = psp_ctrl | (0x1 << 4);
+            } else {
+                psp_ctrl &= ~(0x01 << 4);
+            }
+
+
+            /* FSRT */
+            psp_ctrl = psp_ctrl | (0x1 << 3);
+
+            /*
+             *Three:adjust polarity between codec bit[3:0] of register[0x32] in acm_pm805.h and ssp here
+             *Bitclk Polarity bit[1:0]
+             */
+            /* SCMODE */
+#if 0
+            //psp_ctrl = psp_ctrl | (0x0 << 0);
+            psp_ctrl = psp_ctrl | (0x1 << 0);
+            //psp_ctrl = psp_ctrl | (0x2 << 0);
+            //psp_ctrl = psp_ctrl | (0x3 << 0);
+#else
+            //for test
+            if (0x3 == scmode) {
+                psp_ctrl = psp_ctrl | (0x3 << 0);
+            } else if (0x2 == scmode) {
+                psp_ctrl = psp_ctrl | (0x2 << 0);
+            } else if (0x1 == scmode) {
+                psp_ctrl = psp_ctrl | (0x1 << 0);
+            } else if (0x0 == scmode) {
+                psp_ctrl = psp_ctrl | (0x0 << 0);
+            }
+#endif
+
+            /* PSP_CTRL[0x18] */
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(PSP_CTRL), ssp->mmio_base + PSP_CTRL);
+            } else {
+                __raw_writel(psp_ctrl, ssp->mmio_base + PSP_CTRL);
+            }
+
+            if ((32 == frame_bits) || (16 == frame_bits)) {
+                /* NETWORK_CTRL[0x1C] */
+                /* FRDC: must be needed when slave */
+
+                /* Disable the network mode */
+                if (status_debug_tool) {
+                    __raw_writel(get_reg_value_from_UI(NET_WORK_CTRL), ssp->mmio_base + NET_WORK_CTRL);
+                } else {
+                    __raw_writel(0, ssp->mmio_base + NET_WORK_CTRL);
+                }
+            } else if (64 == frame_bits) {
+                /* Enable the network mode */
+                network_ctrl = network_ctrl | (0x3<<12);/* RX slot time */
+                network_ctrl = network_ctrl | (0x3<<4);/* TX slot time */
+                network_ctrl = network_ctrl | (0x1<<1);/* FRDC */
+                network_ctrl = network_ctrl | (0x1<<0);/* NET_WORK_MOD  */
+
+                if (status_debug_tool) {
+                    __raw_writel(get_reg_value_from_UI(NET_WORK_CTRL), ssp->mmio_base + NET_WORK_CTRL);
+                } else {
+                    __raw_writel(network_ctrl, ssp->mmio_base + NET_WORK_CTRL);
+                }
+            }
+
+            //rwot_ctrl = rwot_ctrl | (1 << 0);
+            //__raw_writel(rwot_ctrl, ssp->mmio_base + RWOT_CTRL);
+
+#if 0
+            top_ctrl |= 1;
+            __raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+#endif
+
+            // printk(KERN_INFO"master: TOP_CTRL 0x%08x FIFO_CTRL 0x%08x PSP_CTRL 0x%08x\n", top_ctrl, fifo_ctrl, psp_ctrl);
+#endif
+        } else {
+            /* ssp is slave */
+#if 1
+            //deleted for debug
+            top_ctrl = 0;
+            fifo_ctrl = 0;
+            int_en = 0;
+            psp_ctrl = 0;
+            network_ctrl = 0;
+            scmode = get_status_SCMODE();
+            status_debug_tool = get_status_debug_tools();
+            //rwot_ctrl = 0;
+
+            //Register:TOP_CTRL[0x00]
+
+            /* TXD Three-State Enable */
+            top_ctrl = top_ctrl | (0x1 << 17);
+
+            /*
+             *One:adjust polarity between codec bit[3:0] of register[0x32] in acm_pm805.h and ssp here
+             *IFS: bit15[TOP_CTRL]
+             */
+            if (get_status_IFS()) {
+                top_ctrl = top_ctrl | (0x01 << 15);
+            } else {
+                top_ctrl &= ~(0x01 << 15);
+            }
+
+            /* TRAIL:bit13 DMA bursts */
+            top_ctrl = top_ctrl | (0x1 << 13);
+
+            if (64 == frame_bits) {
+                /* 32bit data size, Frame format as PSP */
+                top_ctrl = top_ctrl | (0x1f << 5);
+            } else if (32 == frame_bits) {
+                /* 32bit data size, Frame format as PSP */
+                top_ctrl = top_ctrl | (0x1f << 5);
+            } else if (16 == frame_bits) {
+                /* 16bit data size, Frame format as PSP */
+                top_ctrl = top_ctrl | (0x0f << 5);
+            }
+
+            /* slave mode, receive SCLK and SFRM */
+            top_ctrl = top_ctrl | (0x3 << 3);
+            /* master mode, receive SCLK and SFRM */
+            //top_ctrl &= ~(0x3 << 3);
+
+            /* Frame format as PSP */
+            top_ctrl = top_ctrl | (0x3 << 1);
+
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(TOP_CTRL), ssp->mmio_base + TOP_CTRL);
+            } else {
+                __raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+            }
+#if 1
+            /*
+             *Register:FIFO_CTRL[0x04]
+             *Transmit/Receive service request enable
+             *TXFIFO/RXFIFO threshold as 0x8
+             */
+
+            //fifo_ctrl = fifo_ctrl | (0x1 << 16);
+            fifo_ctrl = fifo_ctrl | (0x3 << 10);
+
+            /*RX FIFO Trigger Threshold*/
+            fifo_ctrl = fifo_ctrl | (0x3 << 5);
+
+            /*TX FIFO Trigger Threshold*/
+            fifo_ctrl = fifo_ctrl | (0x3 << 0);
+
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(FIFO_CTRL), ssp->mmio_base + FIFO_CTRL);
+            } else {
+                __raw_writel(fifo_ctrl, ssp->mmio_base + FIFO_CTRL);
+            }
+#else
+            /* test2 */
+            fifo_ctrl = fifo_ctrl | (0x1 << 17); /* RX_AUTO_FULL_CTRL_EN */
+            fifo_ctrl &= ~(0x1 << 16);/* FIFO_UNPACKING  */
+            fifo_ctrl = fifo_ctrl | (0x1 << 11);/* RX_REQ_EN */
+            fifo_ctrl = fifo_ctrl | (0x1 << 10);/* TX_REQ_EN */
+            fifo_ctrl = fifo_ctrl | (0x7 << 5);/* RX_THRES_7 */
+            fifo_ctrl = fifo_ctrl | (0x7 << 0);/* TX_THRES_7 */
+            __raw_writel(fifo_ctrl, ssp->mmio_base + FIFO_CTRL);
+#endif
+
+#if 1
+            __raw_writel(int_en, ssp->mmio_base + INT_EN);
+#else
+            /* test3 */
+            int_en = int_en | (0x1 << 3);/* TX_FIFO_INT_EN */
+            int_en = int_en | (0x1 << 2);/* RX_FIFO_INT_EN */
+            int_en = int_en | (0x1 << 1);/* TIMEOUT_EN */
+            int_en = int_en | (0x1 << 0);/* PERI_TRAIL_EN */
+
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(INT_EN), ssp->mmio_base + INT_EN);
+            } else {
+                __raw_writel(int_en, ssp->mmio_base + INT_EN);
+            }
+#endif
+
+#if 1
+            __raw_writel(0, ssp->mmio_base + TO);
+#else
+            /* test4 */
+            __raw_writel(0x200, ssp->mmio_base + TO);
+#endif
+
+            if (64 == frame_bits) {
+                /* Serial Frame Width:32, SFRMWDTH */
+                psp_ctrl = psp_ctrl | (0x20 << 12);
+            } else if (32 == frame_bits) {
+                /* Register:PSP_CTRL[0x18] */
+                /* SFRMWDTH:must be needed when slave */
+                /* Serial Frame Width:16, SFRMWDTH */
+                psp_ctrl = psp_ctrl | (0x10 << 12);
+            } else if (16 == frame_bits) {
+                /* Serial Frame Width:8, SFRMWDTH */
+                psp_ctrl = psp_ctrl | (0x08 << 12);
+            }
+
+            /*
+             *Two:adjust polarity between codec bit[3:0] of register[0x32] in acm_pm805.h and ssp here
+             *Frame Polarity bit[4]
+             */
+            /* SFRMP */
+            //psp_ctrl = psp_ctrl | (0x1 << 4);
+            if (get_status_SFRMP()) {
+                psp_ctrl = psp_ctrl | (0x1 << 4);
+            } else {
+                psp_ctrl &= ~(0x1 << 4);
+            }
+
+
+            /* FSRT */
+            psp_ctrl = psp_ctrl | (0x1 << 3);
+
+            /*
+             *Three:adjust polarity between codec bit[3:0] of register[0x32] in acm_pm805.h and ssp here
+             *Bitclk Polarity bit[1:0]
+             */
+            /* SCMODE */
+#if 0
+            //psp_ctrl = psp_ctrl | (0x0 << 0);
+            psp_ctrl = psp_ctrl | (0x1 << 0);
+            //psp_ctrl = psp_ctrl | (0x2 << 0);
+            //psp_ctrl = psp_ctrl | (0x3 << 0);
+#else
+            //for debug
+            if (0x3 == scmode) {
+                psp_ctrl = psp_ctrl | (0x3 << 0);
+            } else if (0x2 == scmode) {
+                psp_ctrl = psp_ctrl | (0x2 << 0);
+            } else if (0x1 == scmode) {
+                psp_ctrl = psp_ctrl | (0x1 << 0);
+            } else if (0x0 == scmode) {
+                psp_ctrl = psp_ctrl | (0x0 << 0);
+            }
+#endif
+
+            /* PSP_CTRL[0x18] */
+            if (status_debug_tool) {
+                __raw_writel(get_reg_value_from_UI(PSP_CTRL), ssp->mmio_base + PSP_CTRL);
+            } else {
+                __raw_writel(psp_ctrl, ssp->mmio_base + PSP_CTRL);
+            }
+
+            if ((32 == frame_bits) || (16 == frame_bits)) {
+                /* NETWORK_CTRL[0x1C] */
+                /* FRDC: must be needed when slave */
+
+                /* Disable the network mode */
+                if (status_debug_tool) {
+                    __raw_writel(get_reg_value_from_UI(NET_WORK_CTRL), ssp->mmio_base + NET_WORK_CTRL);
+                } else {
+                    __raw_writel(0, ssp->mmio_base + NET_WORK_CTRL);
+                }
+            } else if (64 == frame_bits) {
+                /* Enable the network mode */
+                network_ctrl = network_ctrl | (0x3<<12);/* RX slot time */
+                network_ctrl = network_ctrl | (0x3<<4);/* TX slot time */
+                network_ctrl = network_ctrl | (0x1<<1);/* FRDC */
+                network_ctrl = network_ctrl | (0x1<<0);/* NET_WORK_MOD  */
+
+                if (status_debug_tool) {
+                    __raw_writel(get_reg_value_from_UI(NET_WORK_CTRL), ssp->mmio_base + NET_WORK_CTRL);
+                } else {
+                    __raw_writel(network_ctrl, ssp->mmio_base + NET_WORK_CTRL);
+                }
+            }
+
+            //rwot_ctrl = rwot_ctrl | (1 << 0);
+            //__raw_writel(rwot_ctrl, ssp->mmio_base + RWOT_CTRL);
+
+#endif
+        }
+
+    }
+
+    //ssp_dump_registers(g_ssp);
+
+    return 0;
+}
+
+static int pxa_sndcard_lofi_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* support narrow band: 8K */
+	cpu_dai->driver->playback.rates = SNDRV_PCM_RATE_8000;
+	cpu_dai->driver->capture.rates = SNDRV_PCM_RATE_8000;
+	codec_dai->driver->playback.channels_max = 1;
+	codec_dai->driver->capture.channels_max = 1;
+
+	return 0;
+}
+
+static int pxa_sndcard_dummy_nb_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* support both 8K*/
+	cpu_dai->driver->playback.rates = SNDRV_PCM_RATE_8000;
+	cpu_dai->driver->capture.rates = SNDRV_PCM_RATE_8000;
+	codec_dai->driver->playback.channels_max = 1;
+	codec_dai->driver->capture.channels_max = 1;
+	codec_dai->driver->playback.formats = SNDRV_PCM_FMTBIT_S32_LE;
+	codec_dai->driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE;
+
+	return 0;
+}
+
+static int pxa_sndcard_dummy_wb_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* support both 16K*/
+	cpu_dai->driver->playback.rates = SNDRV_PCM_RATE_16000;
+	cpu_dai->driver->capture.rates = SNDRV_PCM_RATE_16000;
+	codec_dai->driver->playback.channels_max = 1;
+	codec_dai->driver->capture.channels_max = 1;
+	codec_dai->driver->playback.formats = SNDRV_PCM_FMTBIT_S32_LE;
+	codec_dai->driver->capture.formats = SNDRV_PCM_FMTBIT_S32_LE;
+
+	return 0;
+}
+
+static int pxa_sndcard_pcm_hifi_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+	/* support gssp hifi record: 44.1k */
+	cpu_dai->driver->playback.rates = SNDRV_PCM_RATE_44100;
+	cpu_dai->driver->capture.rates = SNDRV_PCM_RATE_44100;
+	codec_dai->driver->playback.channels_max = 2;
+	codec_dai->driver->capture.channels_max = 2;
+	codec_dai->driver->playback.formats = SNDRV_PCM_FMTBIT_S16_LE;
+	codec_dai->driver->capture.formats = SNDRV_PCM_FMTBIT_S16_LE;
+
+	return 0;
+}
+
+static int pxa_sndcard_lofi_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params)
+{
+	/*
+	 * Since gssp is used for hifi record on HelanLTE A0,
+	 * enable gssp when startup to eliminate noise.
+	 * So move re-init gssp registers to pxa-ssp.c.
+	 * Do nothing here.
+	 */
+	return 0;
+}
+
+static int pxa_sndcard_lofi_prepare(struct snd_pcm_substream *substream)
+{
+	return 0;
+}
+
+//static struct snd_soc_jack hs_jack, hk_jack;
+
+static int pxa_sndcard_late_probe(struct snd_soc_card *card)
+{
+	return 0;
+}
+
+static struct snd_soc_ops pxa_sndcard_machine_ops[] = {
+{
+	.startup = pxa_sndcard_hifi_startup,
+	.hw_params = pxa_sndcard_hw_params,
+	.prepare = pxa_sndcard_hifi_prepare,
+},
+{
+	.startup = pxa_sndcard_lofi_startup,
+	.hw_params = pxa_sndcard_lofi_hw_params,
+	.prepare = pxa_sndcard_lofi_prepare,
+},
+{
+	.startup = pxa_sndcard_dummy_nb_startup,
+	.hw_params = pxa_sndcard_lofi_hw_params,
+	.prepare = pxa_sndcard_lofi_prepare,
+},
+{
+	.startup = pxa_sndcard_dummy_wb_startup,
+	.hw_params = pxa_sndcard_lofi_hw_params,
+	.prepare = pxa_sndcard_lofi_prepare,
+},
+{
+	.startup = pxa_sndcard_pcm_hifi_startup,
+	.hw_params = pxa_sndcard_lofi_hw_params,
+	.prepare = pxa_sndcard_lofi_prepare,
+},
+};
+
+#if defined(CONFIG_CODEC_ALC5616)
+
+SND_SOC_DAILINK_DEFS(alc5616,
+    DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.1")),
+    DAILINK_COMP_ARRAY(COMP_CODEC("alc5616.0-001b", "alc5616-pcm")),
+    DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-ssp-dai.1")));
+
+static struct snd_soc_dai_link pxa_alc5616_dai[] = {
+    {
+        .name = "alc5616 pcm",
+        .stream_name = "mrvl-ssp",
+        .ops = &pxa_sndcard_machine_ops[0],
+        SND_SOC_DAILINK_REG(alc5616),
+    },
+};
+
+static struct snd_soc_card pxa_alc5616_card = {
+    .name = "pxa-alc5616-dkb-voice",
+    .dai_link = pxa_alc5616_dai,
+    .num_links = ARRAY_SIZE(pxa_alc5616_dai),
+    .late_probe = pxa_sndcard_late_probe,
+};
+
+#else
+
+SND_SOC_DAILINK_DEFS(sspbt,
+    DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.1")),
+    DAILINK_COMP_ARRAY(COMP_CODEC("sspbt.0-001c", "sspbt-pcm")),
+    DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-ssp-dai.1")));
+
+static struct snd_soc_dai_link pxa_sspbt_dai[] = {
+    {
+        .name = "sspbt pcm",
+        .stream_name = "mrvl-ssp",
+        .ops = &pxa_sndcard_machine_ops[0],
+        SND_SOC_DAILINK_REG(sspbt),
+    },
+};
+
+static struct snd_soc_card pxa_sspbt_card = {
+    .name = "pxa-sspbt-dkb-voice",
+    .dai_link = pxa_sspbt_dai,
+    .num_links = ARRAY_SIZE(pxa_sspbt_dai),
+    .late_probe = pxa_sndcard_late_probe,
+};
+#endif
+
+#ifdef CONFIG_PM
+static int pxa_sndcard_suspend(struct device *dev)
+{
+	return 0;
+}
+
+static int pxa_sndcard_resume(struct device *dev)
+{
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pxa_sndcard_pm_ops, pxa_sndcard_suspend,
+			 pxa_sndcard_resume);
+
+static struct of_device_id pxa_sndcard_dt_ids[] = {
+	{ .compatible = "ASRMICRO,asrmicro-snd-card", },
+	{}
+};
+MODULE_DEVICE_TABLE(of, pxa_sndcard_dt_ids);
+
+static int pxa_sndcard_probe(struct platform_device *pdev)
+{
+#if defined(CONFIG_CODEC_ALC5616)
+    	struct snd_soc_card *card = &pxa_alc5616_card;
+#else
+    	struct snd_soc_card *card = &pxa_sspbt_card;
+#endif
+
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n",
+			ret);
+
+	/* add ssp_master sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_ssp_master);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"%s: failed to add ssp_master sysfs files: %d\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* add gssp_master sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_gssp_master);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"%s: failed to add gssp_master sysfs files: %d\n",
+			__func__, ret);
+		goto err;
+	}
+
+	/* add gssp_record sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_gssp_record);
+	if (ret < 0) {
+		dev_err(&pdev->dev,
+			"%s: failed to add gssp_record sysfs files: %d\n",
+			__func__, ret);
+		goto err;
+	}
+#ifdef CONFIG_SND_PXA_SSP_DUMP
+	/* add ssp_playback_dump sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_ssp_playback_dump.attr);
+	if (ret < 0)
+		dev_err(&pdev->dev,
+			"%s: failed to add ssp_playback_dump sysfs files: %d\n",
+			__func__, ret);
+	/* add ssp_capture_dump sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_ssp_capture_dump.attr);
+	if (ret < 0)
+		dev_err(&pdev->dev,
+			"%s: failed to add ssp_capture_dump sysfs files: %d\n",
+			__func__, ret);
+	/* add gssp_playback_dump sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_gssp_playback_dump.attr);
+	if (ret < 0)
+		dev_err(&pdev->dev,
+			"%s: failed to add gssp_playback_dump sysfs files: %d\n",
+			__func__, ret);
+	/* add gssp_capture_dump sysfs entries */
+	ret = device_create_file(&pdev->dev, &dev_attr_gssp_capture_dump.attr);
+	if (ret < 0)
+		dev_err(&pdev->dev,
+			"%s: failed to add gssp_capture_dump sysfs files: %d\n",
+			__func__, ret);
+#endif
+	return ret;
+err:
+	snd_soc_unregister_card(card);
+	return ret;
+}
+
+static int pxa_sndcard_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	device_remove_file(&pdev->dev, &dev_attr_ssp_master);
+	device_remove_file(&pdev->dev, &dev_attr_gssp_master);
+#ifdef CONFIG_SND_PXA_SSP_DUMP
+	device_remove_file(&pdev->dev, &dev_attr_ssp_playback_dump.attr);
+	device_remove_file(&pdev->dev, &dev_attr_ssp_capture_dump.attr);
+	device_remove_file(&pdev->dev, &dev_attr_gssp_playback_dump.attr);
+	device_remove_file(&pdev->dev, &dev_attr_gssp_capture_dump.attr);
+#endif
+	snd_soc_unregister_card(card);
+
+	return 0;
+}
+
+static struct platform_driver pxa_sndcard_driver = {
+	.driver		= {
+		.name	= "pxa-sndcard-hifi",
+		.owner	= THIS_MODULE,
+		.of_match_table = pxa_sndcard_dt_ids,
+		.pm             = &pxa_sndcard_pm_ops,
+	},
+	.probe	= pxa_sndcard_probe,
+	.remove	= pxa_sndcard_remove,
+};
+
+module_platform_driver(pxa_sndcard_driver);
+
+/* Module information */
+MODULE_AUTHOR("wenchen@asrmicro.com");
+MODULE_DESCRIPTION("ALSA SoC TTC DKB");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa-sndcard-hifi");
diff --git a/marvell/linux/sound/soc/pxa/pxa-ssp.c b/marvell/linux/sound/soc/pxa/pxa-ssp.c
new file mode 100644
index 0000000..0f0b360
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa-ssp.c
@@ -0,0 +1,2293 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * pxa-ssp.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005,2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ * TODO:
+ *  o Test network mode for > 16bit sample size
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/of.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/platform_data/mmp_audio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/features.h>
+#include <linux/debugfs.h>
+
+#include <asm/irq.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
+#include <linux/dma-mapping.h>
+#include "pxa-ssp.h"
+#include <linux/pxa2xx_ssp.h>
+
+
+extern u32 top_ctrl_hifi;
+extern u32 fifo_ctrl_hifi;
+extern u32 rwot_ctrl_hifi;
+extern u32 network_ctrl_hifi;
+extern u32 int_en_hifi;
+
+extern void set_ssp_role(int role);
+extern int get_ssp_role(void);
+
+static int reg_ssp = 0xffff;
+struct dentry *ssp_dump_reg = NULL;
+struct ssp_device *g_ssp = NULL;
+
+#define APBC_SSP1_CLK_RST_ADDR         (0xD4015020)
+#define PMU_SQU_CLK_GATE_CTRL_ADDR     (0xD428281C)
+#define SQU_CTRL_0_ADDR                (0xD42A0000)
+#define FCCR_ADDR                      (0xD4050008)
+#define ISCCR2_ADDR                    (0xD4050044)
+
+#define ICU_DMA_SEAGULL_INT_STATUS_ADDR   (0xD4282120)
+
+#define DMA_BASE_ADDR                (0xD4000000)
+
+static void __iomem *APBC_SSP1_CLK_RST_reg = NULL;
+static void __iomem *PMU_SQU_CLK_GATE_CTRL_reg = NULL;
+static void __iomem *SQU_CTRL_0_reg = NULL;
+static void __iomem *FCCR_reg = NULL;
+static void __iomem *ISCCR2_reg = NULL;
+
+static void __iomem *ICU_DMA_SEAGULL_INT_STATUS_reg = NULL;
+
+static void __iomem *DMA_BASE_reg = NULL;
+
+/* Debug Master/SLave, Frame sync, BitClk for SSP */
+typedef enum{
+    SSP_BCLK_16_FS = 0,
+    SSP_BCLK_32_FS,
+    SSP_BCLK_64_FS,
+    SSP_BCLK_MAX_FS = SSP_BCLK_64_FS
+} SSP_BCLK_TYPE;
+
+typedef enum{
+    SAMPLE_FREQUENCY_8000 = 0,
+    SAMPLE_FREQUENCY_16000,
+    SAMPLE_FREQUENCY_44100,
+    MAX_SAMPLE_FREQUENCY = SAMPLE_FREQUENCY_44100
+} SAMPLE_FREQUENCY_ID;
+
+typedef enum{
+    SSP_FRAME_BITS_16FS = 0,
+    SSP_FRAME_BITS_32FS,
+    SSP_FRAME_BITS_64FS,
+    SSP_FRAME_BITS_MAX_FS = SSP_FRAME_BITS_64FS
+} SSP_FRAME_BITS;
+
+static int g_gssp_bclk_type = SSP_BCLK_32_FS;
+static int g_switch_frame_bits = SSP_FRAME_BITS_32FS;
+static int g_enable_switch_frame_bits = 0;
+static int g_status_debug_tools = 0;/* debug tools for ssp register */
+static int g_status_IFS = 1;/* SSP_TOP_CTRL bit15 */
+static int g_status_SFRMP = 0;/* SSP_PSP_CTRL bit4 */
+static int g_status_SCMODE = 1;/* SSP_PSP_CTRL bit1~0 0x0~0x3 */
+static int g_frame_bits = (1 << SSP_FRAME_BITS_32FS) * 16;
+static int Audio_WB_AMR_Enable = 0;
+
+u32 top_ctrl_UI = 0;
+u32 fifo_ctrl_UI = 0;
+u32 int_en_UI = 0;
+u32 psp_ctrl_UI = 0;
+u32 network_ctrl_UI = 0;
+
+u32 get_reg_value_from_UI(int offset)
+{
+    if (TOP_CTRL == offset) {
+        /* SSP_TOP_CTRL */
+        return top_ctrl_UI;
+    } else if (FIFO_CTRL == offset) {
+        /* SSP_FIFO_CTRL */
+        return fifo_ctrl_UI;
+    } else if (INT_EN == offset) {
+        /* SSP_INT_CTRL */
+        return int_en_UI;
+    } else if (PSP_CTRL == offset) {
+        /* SSP_PSP_CTRL */
+        return psp_ctrl_UI;
+    } else if (NET_WORK_CTRL == offset) {
+        /* SSP_NET_WORK_CTRL */
+        return network_ctrl_UI;
+    }
+
+    return 0;
+}
+
+/* Enable the clk */
+static void UI_enable_clk(struct ssp_device *ssp)
+{
+    clk_prepare_enable(ssp->clk);
+    return;
+}
+
+/* Disable the clk */
+static void UI_disable_clk(struct ssp_device *ssp)
+{
+    clk_disable_unprepare(ssp->clk);
+
+    return;
+}
+
+/* Enable the ssp */
+static void UI_enable_ssp(struct ssp_device *ssp)
+{
+    uint32_t top_ctrl;
+
+    top_ctrl = __raw_readl(ssp->mmio_base + TOP_CTRL) | TOP_SSE;
+    __raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+    return;
+}
+
+/* Disable the ssp */
+static void UI_disable_ssp(struct ssp_device *ssp)
+{
+    uint32_t top_ctrl;
+
+    top_ctrl = __raw_readl(ssp->mmio_base + TOP_CTRL) & ~TOP_SSE;
+    __raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+    return;
+}
+
+/* Master/Slave switch */
+static void UI_switch_SSP_role(void)
+{
+    int ssp_role;
+
+    ssp_role = get_ssp_role();
+    set_ssp_role(++ssp_role % 2);
+
+    return;
+}
+
+/* Frame sync */
+static void UI_Reverse_WBNB(void)
+{
+    if (Audio_WB_AMR_Enable)
+        Audio_WB_AMR_Enable = 0;
+    else
+        Audio_WB_AMR_Enable = 1;
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, Audio_WB_AMR_Enable is %s.\n", __FUNCTION__, __LINE__, Audio_WB_AMR_Enable?"WB":"NB");
+#endif
+    return;
+}
+
+/* BitClk */
+static int set_BCLK_type(int bclk_type)
+{
+    if(bclk_type > SSP_BCLK_MAX_FS){
+        printk(KERN_INFO"BCLK_MAX_FS = %d, bclk_type = %d.\n", g_gssp_bclk_type, bclk_type);
+
+        return -1;
+    }
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"old = %d, new = %d.\n", g_gssp_bclk_type, bclk_type);
+#endif
+    g_gssp_bclk_type = bclk_type;
+    return 0;
+}
+
+static void UI_switch_bitclk_FS(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"switch_bitclk_fs.\n");
+#endif
+    set_BCLK_type((g_gssp_bclk_type + 1) % 4);
+    return;
+}
+
+/* FRAME BITS */
+static int set_frame_bits(int switch_frame_bits)
+{
+    g_switch_frame_bits = switch_frame_bits;
+    g_frame_bits = (1 << switch_frame_bits) * 16;
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_switch_frame_bits=%d, g_frame_bits=%d.\n", __FUNCTION__, g_switch_frame_bits, g_frame_bits);
+#endif
+    return 0;
+}
+
+int get_frame_bits(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_frame_bits=%d.\n", __FUNCTION__, g_frame_bits);
+#endif
+    return g_frame_bits;
+}
+
+static void UI_switch_frame_bits(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"switch frame bits.\n");
+#endif
+    set_frame_bits((g_switch_frame_bits + 1) % 3);
+    return;
+}
+
+/* Enable/Disable switch frame bits */
+static int enable_switch_frame_bits(int status)
+{
+    g_enable_switch_frame_bits = status;
+
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_enable_switch_frame_bits=%d.\n", __FUNCTION__, g_enable_switch_frame_bits);
+#endif
+    return 0;
+}
+
+int get_status_switch_frame_bits(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_enable_switch_frame_bits=%d.\n", __FUNCTION__, g_enable_switch_frame_bits);
+#endif
+    return g_enable_switch_frame_bits;
+}
+
+static void UI_enable_switch_frame_bits(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"enable/disable switch frame bits.\n");
+#endif
+    enable_switch_frame_bits((g_enable_switch_frame_bits + 1) % 2);
+    return;
+}
+
+/* open debug interface for several registers control in pxa_88pm805_hifi_prepare() pxa-88pm805.c  */
+static int switch_debug_tools(int status)
+{
+    g_status_debug_tools = status;
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_debug_tools=%d.\n", __FUNCTION__, g_status_debug_tools);
+#endif
+    return 0;
+}
+
+int get_status_debug_tools(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_debug_tools=%d.\n", __FUNCTION__, g_status_debug_tools);
+#endif
+    return g_status_debug_tools;
+}
+
+static void UI_switch_debug_tools(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"UI_switch_debug_tools.\n");
+#endif
+    switch_debug_tools((g_status_debug_tools + 1) % 2);
+    return;
+}
+
+/* Display all global control variables */
+static void UI_display_global_ctrl_var(void)
+{
+    printk(KERN_INFO"g_gssp_bclk_type = %d.\n", g_gssp_bclk_type);
+    printk(KERN_INFO"g_switch_frame_bits = %d.\n", g_switch_frame_bits);
+    printk(KERN_INFO"g_enable_switch_frame_bits = %d.\n", g_enable_switch_frame_bits);
+    printk(KERN_INFO"g_status_debug_tools = %d.\n", g_status_debug_tools);
+    printk(KERN_INFO"g_status_IFS = %d.\n", g_status_IFS);
+    printk(KERN_INFO"g_status_SFRMP = %d.\n", g_status_SFRMP);
+    printk(KERN_INFO"g_status_SCMODE = %d.\n", g_status_SCMODE);
+    printk(KERN_INFO"g_frame_bits = %d.\n", g_frame_bits);
+    printk(KERN_INFO"Audio_WB_AMR_Enable = %d.\n", Audio_WB_AMR_Enable);
+
+    return;
+}
+
+/* SSP_TOP_CTRL bit15: IFS = Invert Frame Signal */
+static int switch_IFS(int status)
+{
+    g_status_IFS = status;
+
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_IFS=%d.\n", __FUNCTION__, g_status_IFS);
+#endif
+    return 0;
+}
+
+int get_status_IFS(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_IFS=%d.\n", __FUNCTION__, g_status_IFS);
+#endif
+    return g_status_IFS;
+}
+
+static void UI_switch_IFS(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"UI_switch_IFS.\n");
+#endif
+    switch_IFS((g_status_IFS + 1) % 2);
+    return;
+}
+
+/* SSP_PSP_CTRL bit4: SFRMP = Serial Frame Polarity */
+static int switch_SFRMP(int status)
+{
+    g_status_SFRMP = status;
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_SFRMP=%d.\n", __FUNCTION__, g_status_SFRMP);
+#endif
+    return 0;
+}
+
+int get_status_SFRMP(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_SFRMP=%d.\n", __FUNCTION__, g_status_SFRMP);
+#endif
+    return g_status_SFRMP;
+}
+
+static void UI_switch_SFRMP(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"UI_switch_SFRMP.\n");
+#endif
+    switch_SFRMP((g_status_SFRMP + 1) % 2);
+    return;
+}
+
+/* SSP_PSP_CTRL bit1~0: SCMODE = Serial Bit-rate Clock Mode */
+static int switch_SCMODE(int status)
+{
+    g_status_SCMODE = status;
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_SCMODE=%d.\n", __FUNCTION__, g_status_SCMODE);
+#endif
+    return 0;
+}
+
+int get_status_SCMODE(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s: g_status_SCMODE=%d.\n", __FUNCTION__, g_status_SCMODE);
+#endif
+    return g_status_SCMODE;
+}
+
+static void UI_switch_SCMODE(void)
+{
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"UI_switch_SCMODE.\n");
+#endif
+    switch_SCMODE((g_status_SCMODE + 1) % 4);
+    return;
+}
+
+#if 0
+/* config I2S format */
+static void UI_config_SSP_I2S_format(void)
+{
+    /* write the register */
+    pxa_ssp_write_reg(g_ssp, 0x00, 0x0002a3e7);
+    pxa_ssp_write_reg(g_ssp, 0x04, 0x00000c63);
+    pxa_ssp_write_reg(g_ssp, 0x08, 0x0000000f);
+    pxa_ssp_write_reg(g_ssp, 0x0C, 0x00000200);
+
+    pxa_ssp_write_reg(g_ssp, 0x18, 0x00010009);
+    pxa_ssp_write_reg(g_ssp, 0x1C, 0x00000000);
+
+    /* Enable the ssp */
+    UI_enable_ssp(g_ssp);
+    return;
+}
+
+/* Open SSP clock */
+static void UI_config_APBC_SSP1_CLK_RST(void)
+{
+    uint32_t reg_value = 0;
+#if 1
+    int i;
+
+    /* APBC_SSP1_CLK_RST */
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read before write 0x07: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+    /* Reset ssp1 clock */
+    reg_value = 0x7;
+    iowrite32(reg_value, APBC_SSP1_CLK_RST_reg);
+
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read after write 0x07: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    for (i=0; i<5; i++)
+    {
+    }
+
+    /* Enable SSP1 clock */
+    reg_value = 0x3;
+    iowrite32(reg_value, APBC_SSP1_CLK_RST_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read after write 0x03: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+#endif
+
+}
+
+/* init the SSP clock */
+static void UI_init_SSP_clk(void)
+{
+    uint32_t reg_value = 0;
+#if 0
+    int i;
+
+    /* APBC_SSP1_CLK_RST */
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read before write 0x07: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+    /* Reset ssp1 clock */
+    reg_value = 0x7;
+    iowrite32(reg_value, APBC_SSP1_CLK_RST_reg);
+
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read after write 0x07: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    for (i=0; i<5; i++)
+    {
+    }
+
+    /* Enable SSP1 clock */
+    reg_value = 0x3;
+    iowrite32(reg_value, APBC_SSP1_CLK_RST_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read after write 0x03: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+#endif
+
+    /* PMU_SQU_CLK_GATE_CTRL */
+    reg_value = ioread32(PMU_SQU_CLK_GATE_CTRL_reg);
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, PMU_SQU_CLK_GATE_CTRL: read before write: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+    reg_value &= ~(0x1<<30);
+
+    iowrite32(reg_value, PMU_SQU_CLK_GATE_CTRL_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(PMU_SQU_CLK_GATE_CTRL_reg);
+    printk(KERN_INFO"%s/L%d, PMU_SQU_CLK_GATE_CTRL: read after write: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    /* SQU_CTRL_0 */
+    reg_value = ioread32(SQU_CTRL_0_reg);
+
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, SQU_CTRL_0: read before write: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+    reg_value |= (0x7<<2);
+
+    iowrite32(reg_value, SQU_CTRL_0_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(SQU_CTRL_0_reg);
+    printk(KERN_INFO"%s/L%d, SQU_CTRL_0 : read after write: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+    /* FCCR */
+    reg_value = ioread32(FCCR_reg);
+
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, FCCR: read before write: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    reg_value &= ~(0x1<<28);
+
+    iowrite32(reg_value, FCCR_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(FCCR_reg);
+    printk(KERN_INFO"%s/L%d, FCCR : read after write: reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+    return;
+}
+
+/* test BitClk of ISCCR2 */
+
+static void UI_read_ISCCR2(void)
+{
+    uint32_t reg_value = 0;
+
+    reg_value = ioread32(ISCCR2_reg);
+    printk(KERN_INFO"%s/L%d, ISCCR2: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+
+    return;
+}
+#endif
+
+static void UI_write_ISCCR2(uint32_t write_reg_value)
+{
+#ifdef DEBUG_SSP1
+    uint32_t reg_value;
+
+    reg_value = ioread32(ISCCR2_reg);
+    printk(KERN_INFO"%s/L%d,ISCCR2: read before write: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    iowrite32(write_reg_value, ISCCR2_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(ISCCR2_reg);
+    printk(KERN_INFO"%s/L%d,ISCCR2: read after write: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    return;
+}
+
+static void UI_read_SSP_regs(void)
+{
+    uint32_t reg_value = 0;
+    int i;
+
+    /* APBC_SSP1_CLK_RST */
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read : reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+
+    /* PMU_SQU_CLK_GATE_CTRL */
+    reg_value = ioread32(PMU_SQU_CLK_GATE_CTRL_reg);
+    printk(KERN_INFO"%s/L%d, PMU_SQU_CLK_GATE_CTRL: read : reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+
+    /* SQU_CTRL_0 */
+    reg_value = ioread32(SQU_CTRL_0_reg);
+    printk(KERN_INFO"%s/L%d, SQU_CTRL_0: read : reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+
+    /* FCCR */
+    reg_value = ioread32(FCCR_reg);
+    printk(KERN_INFO"%s/L%d, FCCR: read : reg_value=0x%x.\n", __FUNCTION__, __LINE__, reg_value);
+
+    /* ISCCR2 */
+    reg_value = ioread32(ISCCR2_reg);
+    printk(KERN_INFO"%s/L%d, ISCCR2: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+
+    /* ICU_DMA_SEAGULL_INT_STATUS */
+    reg_value = ioread32(ICU_DMA_SEAGULL_INT_STATUS_reg);
+    printk(KERN_INFO"%s/L%d, DMA_DADRX[0xD4282120]: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+
+    for (i=0; i<=15; i++)
+    {
+        reg_value = ioread32(DMA_BASE_reg + 4*i);
+        printk(KERN_INFO"%s/L%d, DMA_BASE[0xD4000000 + 0x%x]: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, (4*i), reg_value);
+    }
+
+    reg_value = ioread32(DMA_BASE_reg + 0xF0);
+    printk(KERN_INFO"%s/L%d, DMA_BASE[0xD4000000 + 0xF0]: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+
+    for (i=0; i<=64; i++)
+    {
+        reg_value = ioread32(DMA_BASE_reg + 0x200 + 4*i);
+        printk(KERN_INFO"%s/L%d, DMA_BASE[0xD4000000 + 0x%x]: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, (0x200 + 4*i), reg_value);
+    }
+
+    return;
+}
+
+/* SSP1 Clock: APBC_SSP1_CLK_RST */
+#if 0
+static void UI_read_APBC_SSP1_CLK_RST(void)
+{
+    uint32_t reg_value = 0;
+
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+
+    return;
+}
+#endif
+
+static void UI_write_APBC_SSP1_CLK_RST(uint32_t write_reg_value)
+{
+#ifdef DEBUG_SSP1
+    uint32_t reg_value;
+
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read before write: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    iowrite32(write_reg_value, APBC_SSP1_CLK_RST_reg);
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(APBC_SSP1_CLK_RST_reg);
+    printk(KERN_INFO"%s/L%d, APBC_SSP1_CLK_RST: read after write: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    return;
+}
+
+
+/* config SSP bitclk */
+void UI_config_SSP_BCLK(SSP_BCLK_TYPE bclk_type, SAMPLE_FREQUENCY_ID sample_frequency_id)
+{
+    /****************************************************************
+     *                       Base Clock is 156MHz                    *
+     *****************************************************************
+     *F_bit-clock = (156*1024K)*(M/N)/(4,6,8Div)
+     *F_frame-clock = F_bit-clock/Frame-width
+     *              = (156*1024K)*(M/N)/[(4,6,8Div)*Frame_width]
+     *              = (156*1024K)*M/[(4,6,8Div)*Frame_width*N]
+     *
+     *Example:2channels, 44.1KHz, 16bits
+     *M=0x211=529; N=0x07242=29250; Frame_width = 32; (4,6,8Div)=2;
+     *F_frame-clock = (156*1024K)*M/[(4,6,8Div)*Frame_width*N]
+     *              ~=44.1 KHz
+     *
+     ****************************************************************/
+    unsigned int numerator = 0x07242; /* 29250 */
+    unsigned int denominator = 0x060;
+    unsigned int isscr = 0;
+#ifdef DEBUG_SSP1
+    uint32_t reg_value = 0;
+#endif
+    //unsigned int sscr0_frdc = 0;
+
+#ifdef DEBUG_SSP1
+    printk(KERN_INFO"%s/L%d, bclk_type=%d, sample_frequency_id=%d.\n", __FUNCTION__, __LINE__, bclk_type, sample_frequency_id);
+#endif
+
+    if (sample_frequency_id > MAX_SAMPLE_FREQUENCY)
+    {
+        sample_frequency_id = SAMPLE_FREQUENCY_44100;
+    }
+
+    if (bclk_type > SSP_BCLK_MAX_FS)
+    {
+        printk(KERN_INFO"Error. bclk_type=%d.\n", bclk_type);
+        return;
+    }
+
+    /*
+     *bit14~0:NOM
+     */
+    isscr = numerator;
+
+    /*
+     *bit26~15:DENOM
+     */
+    if (sample_frequency_id == SAMPLE_FREQUENCY_8000)
+    {
+        /* 8000 Hz */
+#if 1
+        isscr |= (denominator << (15 + sample_frequency_id + bclk_type - 1));
+#else
+        if (SSP_BCLK_64_FS == bclk_type) {
+            isscr |= (denominator << (15 + sample_frequency_id + 1));
+        } else if (SSP_BCLK_32_FS == bclk_type) {
+            isscr |= (denominator << (15 + sample_frequency_id + 0));
+        } else {
+            /* SSP_BCLK_16_FS */
+            isscr |= (denominator << (15 + sample_frequency_id - 1));
+        }
+#endif
+    }
+    else if (sample_frequency_id == SAMPLE_FREQUENCY_16000)
+    {
+        /* 16000 Hz */
+#if 1
+        isscr |= (denominator << (15 + sample_frequency_id + bclk_type - 1));
+#else
+        if (SSP_BCLK_64_FS == bclk_type) {
+            isscr |= (denominator << (15 + sample_frequency_id + 1));
+        } else if (SSP_BCLK_32_FS == bclk_type) {
+            isscr |= (denominator << (15 + sample_frequency_id + 0));
+        } else {
+            /* SSP_BCLK_16_FS */
+            isscr |= (denominator << (15 + sample_frequency_id - 1));
+        }
+#endif
+    }
+    else if (sample_frequency_id == SAMPLE_FREQUENCY_44100)
+    {
+        /* 44100 Hz */
+        denominator = 0x211; /* 529 */
+#if 1
+        isscr |= (denominator << (15 + bclk_type - 1));
+#else
+        if (SSP_BCLK_64_FS == bclk_type) {
+            isscr |= (denominator << (15 + 1 ));
+        } else if (SSP_BCLK_32_FS == bclk_type) {
+            isscr |= (denominator << (15 + 0));
+        } else {
+            /* SSP_BCLK_16_FS */
+            isscr |= (denominator << (15 - 1));
+        }
+#endif
+    }
+
+    /*
+     *bit31:SYSCLK_EN
+     *bit30:SYSCLK_BASE  <0>=26MHz,<1>=156MHz
+     *bit29:BITCLK_EN
+     *bit28~27:BITCLK_DIV_468
+     */
+#if 1
+    /* DIV_468 = 2 = reserved */
+    isscr |= 0xE0000000;
+#else
+    if (SSP_BCLK_64_FS == bclk_type) {
+        /* DIV_468 = 2 = reserved */
+        isscr |= 0xE0000000;
+    } else if (SSP_BCLK_32_FS == bclk_type) {
+        /* DIV_468 = 2 = reserved */
+        isscr |= 0xE0000000;
+    } else if (SSP_BCLK_16_FS == bclk_type) {
+        /* DIV_468 = 2 = reserved */
+        isscr |= 0xE0000000;
+        /* DIV_468 = 4 */
+        //isscr |= 0xE8000000;
+    }
+#endif
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(ISCCR2_reg);
+    printk(KERN_INFO"%s/L%d,ISCCR2: read before write: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+    /* ISCCR2 */
+    iowrite32(isscr, ISCCR2_reg);
+
+#if 0
+
+    if (wb)
+    {
+        /* Sample frequece: 16K */
+        iowrite32(0xF840130B, ISCCR2_reg);
+    }
+    else
+    {
+        /* Sample frequece: 8K */
+        iowrite32(0xF820130B, ISCCR2_reg);
+    }
+
+#endif
+
+#ifdef DEBUG_SSP1
+    reg_value = ioread32(ISCCR2_reg);
+    printk(KERN_INFO"%s/L%d, ISCCR2: read after write: reg_value=0x%x\n", __FUNCTION__, __LINE__, reg_value);
+#endif
+
+#if 0
+    sscr0_frdc = (1 << bclk_type) - 1;
+    sspConfiguration->SSCR0_HIGH &= (~(0x07 << 8));
+    sspConfiguration->SSCR0_HIGH |= (sscr0_frdc << 8);
+
+    printk(KERN_INFO"GSSP_CLOCK_REG_ADDR:0x%lx, sscr0_frdc: 0x%lx, wb:%d", *(UINT32 *)GSSP_CLOCK_REG_ADDR, sscr0_frdc, wb);
+#endif
+
+    return;
+
+}
+
+#if 0
+static void test_ssp1(void)
+{
+    UI_config_APBC_SSP1_CLK_RST();
+    UI_init_SSP_clk();
+    //UI_config_SSP_BCLK(g_gssp_bclk_type, Audio_WB_AMR_Enable);
+    UI_config_SSP_BCLK(SSP_BCLK_32_FS, SAMPLE_FREQUENCY_44100);
+    UI_config_SSP_I2S_format();
+
+    return;
+}
+#endif
+
+/*
+ * SSP audio private data
+ */
+struct ssp_priv {
+	struct ssp_device *ssp;
+	unsigned int sysclk;
+	int dai_fmt;
+	unsigned int burst_size;
+	struct pinctrl *pinctrl;
+	struct pinctrl_state *pin_ssp;
+	struct pinctrl_state *pin_gpio;
+	int mfp;
+	int usr_cnt;
+	bool mfp_init;
+#ifdef CONFIG_PM
+	uint32_t	cr0;
+	uint32_t	cr1;
+	uint32_t	to;
+	uint32_t	psp;
+	uint32_t	top_ctrl;
+	uint32_t	fifo_ctrl;
+	uint32_t	int_en;
+	uint32_t	network_ctrl;
+	uint32_t	rwot_ctrl;
+#endif
+	/*
+	 * FixMe: for port 5 (gssp), it is shared by ap
+	 * and cp. When AP want to handle it, AP need to
+	 * configure APB to connect gssp. Also reset gssp
+	 * clk to clear the potential impact from cp
+	 */
+	void __iomem	*apbcp_base;
+};
+
+static ssize_t ssp_mfp_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct ssp_priv *priv = dev_get_drvdata(dev);
+	if (!priv)
+		return sprintf(buf, "%s\n", "get ssp-priv failed!!!\n");
+
+	if (priv->ssp->port_id == 2)
+		printk(KERN_INFO"i2s pin mfp setting:\n");
+	else if (priv->ssp->port_id == 5)
+		printk(KERN_INFO"gssp pin mfp setting:\n");
+
+	return sprintf(buf, "%s\n", (priv->mfp ? "ssp" : "gpio"));
+}
+
+static ssize_t ssp_mfp_set(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	int ret, i;
+	u32 pins_ssp;
+	struct ssp_priv *priv = dev_get_drvdata(dev);
+	struct device_node *np = dev->of_node;
+
+	if (!priv)
+		return -EINVAL;
+
+	if (IS_ERR(priv->pin_ssp) || IS_ERR(priv->pin_gpio))
+		return -EINVAL;
+
+	ret = kstrtoint(buf, 10, &priv->mfp);
+	if (ret)
+		return ret;
+
+	/* mfp = 0, set to gpio; mfp = 1, set to ssp */
+	if (priv->mfp) {
+		ret = pinctrl_select_state(priv->pinctrl, priv->pin_ssp);
+		if (ret) {
+			dev_err(dev, "could not set ssp pins\n");
+			goto err_out;
+		}
+	} else {
+		ret = pinctrl_select_state(priv->pinctrl, priv->pin_gpio);
+		if (ret) {
+			dev_err(dev, "could not set default(gpio) pins\n");
+			goto err_out;
+		}
+
+		for (i = 0; i < 4; i++) {
+			pins_ssp = of_get_named_gpio(np, "ssp-gpio", i);
+			gpio_request(pins_ssp, NULL);
+			gpio_direction_input(pins_ssp);
+			gpio_free(pins_ssp);
+		}
+	}
+
+	if (priv->ssp->port_id == 2)
+		printk(KERN_INFO"i2s pin set to %s\n", (priv->mfp ? "ssp" : "gpio"));
+	else if (priv->ssp->port_id == 5)
+		printk(KERN_INFO"gssp pin set to %s\n", (priv->mfp ? "ssp" : "gpio"));
+
+err_out:
+	return count;
+}
+
+static DEVICE_ATTR(gssp_mfp, 0644, ssp_mfp_show, ssp_mfp_set);
+static DEVICE_ATTR(ssp_mfp, 0644, ssp_mfp_show, ssp_mfp_set);
+
+static void dump_registers(struct ssp_device *ssp)
+{
+	dev_dbg(&ssp->pdev->dev, "TOP_CTRL 0x%08x FIFO_CTRL 0x%08x INT_EN 0x%08x\n",
+		 pxa_ssp_read_reg(ssp, TOP_CTRL), pxa_ssp_read_reg(ssp, FIFO_CTRL),
+		 pxa_ssp_read_reg(ssp, INT_EN));
+
+	dev_dbg(&ssp->pdev->dev, "NET_WORK_CTRL 0x%08x RWOT_CTRL 0x%08x TO 0x%08x\n",
+		 pxa_ssp_read_reg(ssp, NET_WORK_CTRL), pxa_ssp_read_reg(ssp, RWOT_CTRL),
+		 pxa_ssp_read_reg(ssp, TO));
+
+	dev_dbg(&ssp->pdev->dev, "PSP_CTRL 0x%08x STATUS 0x%08x NET_WORK_STATUS 0x%08x\n",
+		 pxa_ssp_read_reg(ssp, PSP_CTRL), pxa_ssp_read_reg(ssp, STATUS),
+		 pxa_ssp_read_reg(ssp, NET_WORK_STATUS));
+}
+
+static void pxa_ssp_enable(struct ssp_device *ssp)
+{
+	uint32_t top_ctrl;
+
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id)) {
+		top_ctrl_hifi |= TOP_SSE;
+		__raw_writel(top_ctrl_hifi, ssp->mmio_base + TOP_CTRL);
+	} else {
+		top_ctrl = __raw_readl(ssp->mmio_base + TOP_CTRL) | TOP_SSE;
+		__raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+	}
+}
+
+static void pxa_ssp_disable(struct ssp_device *ssp)
+{
+	uint32_t top_ctrl;
+
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id)) {
+		top_ctrl_hifi |= TOP_SSE;
+		__raw_writel(top_ctrl_hifi, ssp->mmio_base + TOP_CTRL);
+	} else {
+		top_ctrl = __raw_readl(ssp->mmio_base + TOP_CTRL) & ~TOP_SSE;
+		__raw_writel(top_ctrl, ssp->mmio_base + TOP_CTRL);
+	}
+
+}
+
+static void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4,
+			int out, struct snd_dmaengine_dai_dma_data *dma)
+{
+	dma->addr_width = width4 ? DMA_SLAVE_BUSWIDTH_4_BYTES :
+				   DMA_SLAVE_BUSWIDTH_2_BYTES;
+
+	if (dma->maxburst > PXA_SSP_FIFO_DEPTH)
+		dma->maxburst = PXA_SSP_FIFO_DEPTH;
+
+	dma->addr = ssp->phys_base + DATAR;
+}
+
+static int pxa_ssp_startup(struct snd_pcm_substream *substream,
+			   struct snd_soc_dai *cpu_dai)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+	struct snd_dmaengine_dai_dma_data *dma;
+	int ret = 0;
+
+	ret = pinctrl_select_state(priv->pinctrl, priv->pin_ssp);
+	if (ret) {
+		dev_err(cpu_dai->dev, "could not set ssp pins\n");
+		return ret;
+	}
+	priv->mfp_init = true;
+	priv->mfp = 1;
+
+	if (!cpu_dai->active)
+	{
+		clk_prepare_enable(ssp->clk);
+		priv->usr_cnt = 0;
+	}
+
+	dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL);
+	if (!dma)
+		return -ENOMEM;
+#if 0
+	dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
+				&ssp->drcmr_tx : &ssp->drcmr_rx;
+#endif
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma);
+
+#ifdef DEBUG_SSP1
+	printk(KERN_INFO"%s: drcmr_tx=%d, drcmr_rx=%d.\n", __FUNCTION__, ssp->drcmr_tx, ssp->drcmr_rx);
+#endif
+	return ret;
+}
+
+static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
+			     struct snd_soc_dai *cpu_dai)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+	int ret = 0;
+
+	if (!cpu_dai->active) {
+		pxa_ssp_disable(ssp);
+		clk_disable_unprepare(ssp->clk);
+
+		ret = pinctrl_select_state(priv->pinctrl, priv->pin_gpio);
+		if (ret) {
+			dev_err(cpu_dai->dev, "could not set GPIO pins\n");
+		}
+	}
+
+	kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
+	snd_soc_dai_set_dma_data(cpu_dai, substream, NULL);
+}
+
+#ifdef CONFIG_PM
+
+static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
+{
+	return 0;
+}
+
+static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
+{
+	return 0;
+}
+
+#else
+#define pxa_ssp_suspend	NULL
+#define pxa_ssp_resume	NULL
+#endif
+
+
+/*
+ * Set the SSP ports SYSCLK.
+ */
+static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+	int clk_id, unsigned int freq, int dir)
+{
+	return 0;
+}
+
+/*
+ * Set the SSP clock dividers.
+ */
+static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+	int div_id, int div)
+{
+	return 0;
+}
+
+/*
+ * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
+ */
+static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+	int source, unsigned int freq_in, unsigned int freq_out)
+{
+	return 0;
+}
+
+/*
+ * Set the active slots in TDM/Network mode
+ */
+static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
+	unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+
+	u32 network_ctrl, top_ctrl;
+
+	network_ctrl = pxa_ssp_read_reg(ssp, NET_WORK_CTRL);
+	top_ctrl = pxa_ssp_read_reg(ssp, TOP_CTRL);
+
+	network_ctrl &= ~(NET_FRDC(8) | NET_WORK_MODE | RTSA_MASK | TTSA_MASK);
+	top_ctrl &= ~TOP_DSS_MASK;
+
+	top_ctrl |= TOP_DSS(slot_width);
+
+	if (slots > 1) {
+		/* enable network mode */
+		network_ctrl |= NET_WORK_MODE;
+
+		/* set number of active slots */
+		network_ctrl |= NET_FRDC(slots);
+
+		/* set active slot mask */
+		network_ctrl |= TTSA(tx_mask);
+		network_ctrl |= RTSA(rx_mask);
+	}
+	pxa_ssp_write_reg(ssp, TOP_CTRL, top_ctrl);
+	pxa_ssp_write_reg(ssp, NET_WORK_CTRL, network_ctrl);
+
+	return 0;
+}
+
+/*
+ * Tristate the SSP DAI lines
+ */
+static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
+	int tristate)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+
+	u32 top_ctrl;
+
+	top_ctrl = pxa_ssp_read_reg(ssp, TOP_CTRL);
+	if (tristate)
+		top_ctrl &= ~TOP_TTE;
+	else
+		top_ctrl |= TOP_TTE;
+	pxa_ssp_write_reg(ssp, TOP_CTRL, top_ctrl);
+
+	return 0;
+}
+
+/*
+ * Set up the SSP DAI format.
+ * The SSP Port must be inactive before calling this function as the
+ * physical interface format is changed.
+ */
+static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+	u32 network_ctrl, fifo_ctrl, top_ctrl, psp_ctrl, rwot_ctrl;
+
+	/* check if we need to change anything at all */
+	if (priv->dai_fmt == fmt)
+		return 0;
+
+	/* we can only change the settings if the port is not in use */
+	if (priv->usr_cnt) {
+		dev_err(&ssp->pdev->dev,
+			"can't change hardware dai format: stream is in use");
+		return -EINVAL;
+	}
+
+	/* reset port settings */
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id))
+		network_ctrl = network_ctrl_hifi & ~NET_WORK_MODE;
+	else
+		network_ctrl = pxa_ssp_read_reg(ssp, NET_WORK_CTRL) &
+			~NET_WORK_MODE;
+	fifo_ctrl = FIFO_RFT(7) | FIFO_TFT(7);
+	psp_ctrl = pxa_ssp_read_reg(ssp, PSP_CTRL);
+	top_ctrl = pxa_ssp_read_reg(ssp, TOP_CTRL);
+	rwot_ctrl =pxa_ssp_read_reg(ssp, RWOT_CTRL);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+		top_ctrl |= TOP_SFRMDIR | TOP_SCLKDIR | TOP_SCFR;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		top_ctrl |= TOP_SCLKDIR | TOP_SCFR;
+		break;
+	case SND_SOC_DAIFMT_CBS_CFS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+        //psp_ctrl |= PSP_SFRMP;
+        psp_ctrl |= 0;
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		psp_ctrl |= PSP_SCMODE(2);
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+        //psp_ctrl |= PSP_SCMODE(2) | PSP_SFRMP;
+        psp_ctrl |= PSP_SCMODE(2);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		top_ctrl |= TOP_FRF_PSP;
+		top_ctrl |= TOP_TRAIL;
+		rwot_ctrl = RWOT_RWOT;
+		/* See hw_params() */
+		break;
+
+	case SND_SOC_DAIFMT_DSP_A:
+		psp_ctrl |= PSP_FSRT;
+	case SND_SOC_DAIFMT_DSP_B:
+		top_ctrl |= TOP_FRF_PSP;
+		top_ctrl |= TOP_TRAIL;
+		network_ctrl |= NET_WORK_MODE;
+		rwot_ctrl = RWOT_RWOT;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id)) {
+		top_ctrl_hifi = top_ctrl;
+		fifo_ctrl_hifi = fifo_ctrl;
+		rwot_ctrl_hifi = rwot_ctrl;
+		network_ctrl_hifi = network_ctrl;
+	}
+	pxa_ssp_write_reg(ssp, TOP_CTRL, top_ctrl);
+	pxa_ssp_write_reg(ssp, FIFO_CTRL, fifo_ctrl);
+	pxa_ssp_write_reg(ssp, NET_WORK_CTRL, network_ctrl);
+	pxa_ssp_write_reg(ssp, RWOT_CTRL, rwot_ctrl); 
+	pxa_ssp_write_reg(ssp, PSP_CTRL, psp_ctrl);
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBM_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+		if ((has_feat_hifi_gssp_record())
+			&& (2 == ssp->port_id))
+			top_ctrl = top_ctrl_hifi | TOP_SCFR;
+		else
+			top_ctrl = pxa_ssp_read_reg(ssp, TOP_CTRL) | TOP_SCFR;
+		pxa_ssp_write_reg(ssp, TOP_CTRL, top_ctrl);
+
+		while (pxa_ssp_read_reg(ssp, STATUS) & STATUS_BSY)
+			cpu_relax();
+		break;
+	}
+
+	dump_registers(ssp);
+
+#if 0
+    if (get_ssp_role())
+    {
+        /* parameters: 32FS, 44.1k */
+        UI_config_SSP_BCLK(0, 2);
+
+        /* parameters: 32FS, WB:16k */
+        //UI_config_SSP_BCLK(0, 1);
+
+        /* parameters: 32FS, NB:8k */
+        //UI_config_SSP_BCLK(0, 0);
+    }
+#endif
+
+	/* Since we are configuring the timings for the format by hand
+	 * we have to defer some things until hw_params() where we
+	 * know parameters like the sample size.
+	 */
+	priv->dai_fmt = fmt;
+
+	return 0;
+}
+
+/*
+ * Set the SSP audio DMA parameters and sample size.
+ * Can be called multiple times by oss emulation.
+ */
+static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *cpu_dai)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+	int chn = params_channels(params);
+	u32 top_ctrl;
+	u32 psp_ctrl;
+	u32 network_ctrl;
+	int ttsa;
+	int width = snd_pcm_format_physical_width(params_format(params));
+	struct snd_dmaengine_dai_dma_data *dma_data;
+
+	unsigned int rate = params_rate(params);
+#if 0
+	unsigned int sample_bits = snd_pcm_format_physical_width(params_format(params));
+	unsigned int frame_bits = sample_bits * channels;
+
+	if (get_ssp_role())
+	{
+		if (get_status_switch_frame_bits()){
+			/* for debug */
+			frame_bits = get_frame_bits();
+		} else {
+			/* get frame length from file format */
+			frame_bits = sample_bits * channels;
+		}
+
+		//clk_set_rate(ssp->clk, 2048000);//2.048MHz
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+			clk_set_rate(ssp->clk, rate * 32);
+		} else {
+			//clk_set_rate(ssp->clk, 6500000);//Record ok
+			clk_set_rate(ssp->clk, rate * 32);
+		}
+
+		//UI_read_SSP_regs();
+
+		if ((8000 == rate)  && (64 == frame_bits))
+		{
+			/* parameters: 64FS, NB:8k */
+			UI_config_SSP_BCLK(SSP_BCLK_64_FS, SAMPLE_FREQUENCY_8000);
+		}
+		else if ((16000 == rate)  && (64 == frame_bits))
+		{
+			/* parameters: 64FS, WB:16k */
+			UI_config_SSP_BCLK(SSP_BCLK_64_FS, SAMPLE_FREQUENCY_16000);
+		}
+		else if ((44100 == rate) && (64 == frame_bits))
+		{
+			/* parameters: 64FS, 44.1k */
+			UI_config_SSP_BCLK(SSP_BCLK_64_FS, SAMPLE_FREQUENCY_44100);
+		}
+		else if ((8000 == rate)  && (32 == frame_bits))
+		{
+            /* parameters: 32FS, NB:8k */
+            UI_config_SSP_BCLK(SSP_BCLK_32_FS, SAMPLE_FREQUENCY_8000);
+		}
+		else if ((16000 == rate)  && (32 == frame_bits))
+		{
+			/* parameters: 32FS, WB:16k */
+			UI_config_SSP_BCLK(SSP_BCLK_32_FS, SAMPLE_FREQUENCY_16000);
+		}
+		else if ((44100 == rate) && (32 == frame_bits))
+		{
+			/* parameters: 32FS, 44.1k */
+			UI_config_SSP_BCLK(SSP_BCLK_32_FS, SAMPLE_FREQUENCY_44100);
+		}
+		else if ((8000 == rate)  && (16 == frame_bits))
+		{
+			/* parameters: 16FS, NB:8k */
+			UI_config_SSP_BCLK(SSP_BCLK_16_FS, SAMPLE_FREQUENCY_8000);
+		}
+		else if ((16000 == rate)  && (16 == frame_bits))
+		{
+			/* parameters: 16FS, WB:16k */
+			UI_config_SSP_BCLK(SSP_BCLK_16_FS, SAMPLE_FREQUENCY_16000);
+		}
+		else if ((44100 == rate) && (16 == frame_bits))
+		{
+			/* parameters: 16FS, 44.1k */
+			UI_config_SSP_BCLK(SSP_BCLK_16_FS, SAMPLE_FREQUENCY_44100);
+		}
+	}
+#endif
+    /* the bitclk rate depends on the sample rate, the sample size and chn*/
+	clk_set_rate(ssp->clk, rate * width * chn);
+	network_ctrl = pxa_ssp_read_reg(ssp, NET_WORK_CTRL);
+	ttsa = (network_ctrl & TTSA_MASK) >> TTSA_BASE;
+
+	dma_data = snd_soc_dai_get_dma_data(cpu_dai, substream);
+
+	dma_data->maxburst = priv->burst_size;
+
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id))
+		ttsa = 0;
+	/* Network mode with one active slot (ttsa == 1) can be used
+	 * to force 16-bit frame width on the wire (for S16_LE), even
+	 * with two channels. Use 16-bit DMA transfers for this case.
+	 */
+
+	pxa_ssp_set_dma_params(ssp,
+		((chn == 2) && (ttsa != 1)) || (width == 32),
+		substream->stream == SNDRV_PCM_STREAM_PLAYBACK, dma_data);
+
+	/* we can only change the settings if the port is not in use */
+	if (priv->usr_cnt)
+		return 0;
+
+	/* clear selected SSP bits */
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id))
+		top_ctrl = top_ctrl_hifi & ~(TOP_DSS_MASK);
+	else
+		top_ctrl = pxa_ssp_read_reg(ssp, TOP_CTRL) &
+			~(TOP_DSS_MASK);
+
+	/* bit size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		top_ctrl |= TOP_DSS(16);
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		top_ctrl |= TOP_DSS(24);
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		top_ctrl |= TOP_DSS(32);
+		break;
+	}
+	if ((has_feat_hifi_gssp_record())
+		&& (2 == ssp->port_id))
+		top_ctrl_hifi = top_ctrl;
+	pxa_ssp_write_reg(ssp, TOP_CTRL, top_ctrl);
+
+	switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		psp_ctrl = pxa_ssp_read_reg(ssp, PSP_CTRL);
+
+		/* The frame width is the width the LRCLK is
+		 * asserted for; the delay is expressed in
+		 * half cycle units.  We need the extra cycle
+		 * because the data starts clocking out one BCLK
+		 * after LRCLK changes polarity.
+		 */
+		psp_ctrl |= PSP_SFRMWDTH(width + 1);
+		psp_ctrl |= PSP_FSRT;
+
+		pxa_ssp_write_reg(ssp, PSP_CTRL, psp_ctrl);
+		break;
+	default:
+		break;
+	}
+
+	/* When we use a network mode, we always require TDM slots
+	 * - complain loudly and fail if they've not been set up yet.
+	 */
+	if ((network_ctrl & NET_WORK_MODE) && !ttsa) {
+		dev_err(&ssp->pdev->dev, "No TDM timeslot configured\n");
+		return -EINVAL;
+	}
+
+	dump_registers(ssp);
+	return 0;
+}
+
+static void pxa_ssp_set_running_bit(struct snd_pcm_substream *substream,
+				    struct ssp_device *ssp, int value)
+{
+	uint32_t fifo_ctrl = pxa_ssp_read_reg(ssp, FIFO_CTRL);
+
+	/*
+	 * here we only enable/disable SSP TX/RX DMA request. ssp enable/
+	 * disable is handled in startup/shutdown to avoid noise.
+	 */
+	if ((has_feat_hifi_gssp_record())
+		&& (ssp->port_id == 2))
+		fifo_ctrl = fifo_ctrl_hifi;
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		if (value)
+			fifo_ctrl |= FIFO_TSRE;
+		else
+			fifo_ctrl &= ~FIFO_TSRE;
+	} else {
+		if (value)
+			fifo_ctrl |= FIFO_RSRE;
+		else
+			fifo_ctrl &= ~FIFO_RSRE;
+	}
+
+	if ((has_feat_hifi_gssp_record())
+		&& (ssp->port_id == 2))
+		fifo_ctrl_hifi = fifo_ctrl;
+	pxa_ssp_write_reg(ssp, FIFO_CTRL, fifo_ctrl);
+}
+
+static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
+			   struct snd_soc_dai *cpu_dai)
+{
+	int ret = 0;
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai);
+	struct ssp_device *ssp = priv->ssp;
+	int val;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_RESUME:
+		pxa_ssp_enable(ssp);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		pxa_ssp_set_running_bit(substream, ssp, 1);
+
+		val = pxa_ssp_read_reg(ssp, STATUS);
+		pxa_ssp_write_reg(ssp, STATUS, val);
+
+		break;
+	case SNDRV_PCM_TRIGGER_START:
+		priv->usr_cnt++;
+		pxa_ssp_set_running_bit(substream, ssp, 1);
+		if(1 == priv->usr_cnt){
+		    pxa_ssp_enable(ssp);
+		}
+
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+		priv->usr_cnt--;
+		pxa_ssp_set_running_bit(substream, ssp, 0);
+		if(0 == priv->usr_cnt){
+		    pxa_ssp_disable(ssp);
+		}
+		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		pxa_ssp_disable(ssp);
+		break;
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		pxa_ssp_set_running_bit(substream, ssp, 0);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+
+	dump_registers(ssp);
+
+	return ret;
+}
+
+/* ssp_dump_reg */
+/* debug fs for ssp register interface of read and write. */
+void ssp_dump_registers(struct ssp_device *ssp)
+{
+    printk(KERN_INFO"[SSP_TOP_CTRL:0xD401B800]=0x%08x.\n",  pxa_ssp_read_reg(ssp, TOP_CTRL));/* 0x00 */
+    printk(KERN_INFO"[SSP_FIFO_CTRL:0xD401B804]=0x%08x.\n", pxa_ssp_read_reg(ssp, FIFO_CTRL));/* 0x04 */
+    printk(KERN_INFO"[SSP_INT_EN:0xD401B808]=0x%08x.\n", pxa_ssp_read_reg(ssp, INT_EN));/* 0x08 */
+    printk(KERN_INFO"[SSP_TO:0xD401B80C]=0x%08x\n", pxa_ssp_read_reg(ssp, TO));/* 0x0C */
+
+    printk(KERN_INFO"[SSP_DATAR:0xD401B810]=0x%08x.\n", pxa_ssp_read_reg(ssp, DATAR));/* 0x10 */
+    printk(KERN_INFO"[SSP_STATUS:0xD401B814]=0x%08x.\n", pxa_ssp_read_reg(ssp, STATUS));/* 0x14 */
+    printk(KERN_INFO"[SSP_PSP_CTRL:0xD401B818]=0x%08x.\n",  pxa_ssp_read_reg(ssp, PSP_CTRL));/* 0x18 */
+    printk(KERN_INFO"[SSP_NET_WORK_CTRL:0xD401B81C]=0x%08x.\n", pxa_ssp_read_reg(ssp, NET_WORK_CTRL));/* 0x1C */
+
+    printk(KERN_INFO"[SSP_NET_WORK_STATUS:0xD401B820]=0x%08x.\n", pxa_ssp_read_reg(ssp, NET_WORK_STATUS));/* 0x20 */
+    printk(KERN_INFO"[SSP_RWOT_CTRL:0xD401B824]=0x%08x\n", pxa_ssp_read_reg(ssp, RWOT_CTRL));/* 0x24 */
+    printk(KERN_INFO"[SSP_RWOT_CCM:0xD401B828]=0x%08x.\n", pxa_ssp_read_reg(ssp, RWOT_CCM));/* 0x28 */
+    printk(KERN_INFO"[SSP_RWOT_CVWRn:0xD401B82C]=0x%08x.\n", pxa_ssp_read_reg(ssp, RWOT_CVWRn));/* 0x2C */
+
+    UI_read_SSP_regs();
+
+    printk(KERN_INFO"[top_ctrl_UI=0x%08x. suggested value Slave=0x0002a3fe, Master=0x0002a3e6 for L/R 16bits.\n", top_ctrl_UI);/* 0x00 */
+    printk(KERN_INFO"[fifo_ctrl_UI=0x%08x.suggested value=0x00000c63 for L/R 16bits.\n", fifo_ctrl_UI);/* 0x04 */
+    printk(KERN_INFO"[int_en_UI=0x%08x.suggested value=0x0000000f for L/R 16bits.\n", int_en_UI);/* 0x08 */
+    printk(KERN_INFO"[psp_ctrl_UI=0x%08x.suggested value=0x00010009 for L/R 16bits.\n",  psp_ctrl_UI);/* 0x18 */
+    printk(KERN_INFO"[network_ctrl_UI=0x%08x.suggested value=0x00000000 for L/R 16bits.\n", network_ctrl_UI);/* 0x1C */
+}
+
+static ssize_t ssp_dump_read(struct file *file, char __user *user_buf,
+        size_t count, loff_t *ppos)
+{
+    uint32_t reg_val = 0;
+
+    if (reg_ssp == 0xffff) {
+        /* dump all registers */
+        printk(KERN_INFO"%s/L%d:dump all registers.\n", __FUNCTION__, __LINE__);
+        ssp_dump_registers(g_ssp);
+    } else {
+        /* read the register for reg_ssp */
+        reg_val = pxa_ssp_read_reg(g_ssp, reg_ssp);
+        printk(KERN_INFO"%s/L%d:[0x%02x]=0x%08x.\n", __FUNCTION__, __LINE__, reg_ssp, reg_val);
+    }
+
+    return 0;
+}
+
+/*
+ *read all registers:
+ *echo + > /sys/kernel/debug/ssp_reg
+ *
+ *read offset of register:
+ *echo 0x00 > /sys/kernel/debug/ssp_reg
+ *
+ *write offset of register:
+ *echo 0x00 0x0000a3ff > /sys/kernel/debug/ssp_reg
+ *
+ */
+static ssize_t ssp_dump_write(struct file *file,
+        const char __user *user_buf,
+        size_t count, loff_t *ppos)
+{
+    uint32_t reg_val;
+    //uint32_t reg_val_SSP_TOP_CTRL;
+    int i = 0;
+
+    char messages[20];
+    memset(messages, '\0', 20);
+
+    if (copy_from_user(messages, user_buf, count))
+        return -EFAULT;
+
+    if ('+' == messages[0]) {
+        /* enable to get all the reg value */
+        reg_ssp = 0xffff;
+        /* dump all registers */
+        printk(KERN_INFO"%s/L%d:dump all registers.\n", __FUNCTION__, __LINE__);
+        ssp_dump_registers(g_ssp);
+
+    } else {
+        if (messages[1] != 'x') {
+            pr_err("Right format: 0x[addr]\n");
+            return -EINVAL;
+        }
+
+        if (strlen(messages) > 5) {
+            while (messages[i] != ' ')
+                i++;
+            messages[i] = '\0';
+            if (kstrtouint(messages, 16, &reg_ssp) < 0)
+                return -EINVAL;
+            i++;
+            if (kstrtouint(messages + i, 16, &reg_val) < 0)
+                return -EINVAL;
+
+            printk(KERN_INFO"%s/L%d: [0x%02x]=0x%08x.\n", __FUNCTION__, __LINE__, reg_ssp, reg_val);
+
+            if (reg_ssp == 0xFF)
+            {
+                /* write the ISCCR2 */
+                UI_write_ISCCR2(reg_val);
+            }
+            else if (reg_ssp == 0xEE)
+            {
+                /* write the APBC_SSP1_CLK_RST */
+                UI_write_APBC_SSP1_CLK_RST(reg_val);
+            }
+            else
+            {
+                if (TOP_CTRL == reg_ssp) {
+                    /* SSP_TOP_CTRL */
+                    top_ctrl_UI = reg_val;
+                    printk(KERN_INFO"suggest top_ctrl_UI with Slave=0x0002a3fe, Master=0x0002a3e6 for L/R 16bits.\n");/* 0x00 */
+                } else if (FIFO_CTRL == reg_ssp) {
+                    /* SSP_FIFO_CTRL */
+                    fifo_ctrl_UI = reg_val;
+                    printk(KERN_INFO"suggest fifo_ctrl_UI with 0x00000c63 for L/R 16bits.\n");
+                } else if (INT_EN == reg_ssp) {
+                    /* SSP_INT_CTRL */
+                    int_en_UI = reg_val;
+                    printk(KERN_INFO"suggest int_en_UI with 0x0000000f for L/R 16bits.\n");
+                } else if (PSP_CTRL == reg_ssp) {
+                    /* SSP_PSP_CTRL */
+                    psp_ctrl_UI = reg_val;
+                    printk(KERN_INFO"suggest psp_ctrl_UI with 0x00010009 for L/R 16bits.\n");
+                } else if (NET_WORK_CTRL == reg_ssp) {
+                    /* SSP_NET_WORK_CTRL */
+                    network_ctrl_UI = reg_val;
+                    printk(KERN_INFO"suggest psp_ctrl_UI with 0x00000000 for L/R 16bits.\n");
+                }
+            }
+
+        } else {
+            /* point out the register address for read. */
+            if (kstrtouint(messages, 16, &reg_ssp) < 0)
+                return -EINVAL;
+
+            /* read the register for reg_ssp */
+            reg_val = pxa_ssp_read_reg(g_ssp, reg_ssp);
+            //reg_val = ioread32(ssp1_reg_addr);
+            printk(KERN_INFO"%s/L%d:[0x%02x]=0x%08x.\n", __FUNCTION__, __LINE__, reg_ssp, reg_val);
+        }
+    }
+
+    return count;
+}
+
+static const struct file_operations ssp_dump_ops = {
+    .owner      = THIS_MODULE,
+    .open       = simple_open,
+    .read       = ssp_dump_read,
+    .write      = ssp_dump_write,
+};
+
+static inline int ssp_dump_debugfs_init(void)
+{
+
+    ssp_dump_reg = debugfs_create_file("ssp_reg", S_IRUGO | S_IFREG,
+            NULL, NULL, &ssp_dump_ops);
+
+    if (ssp_dump_reg == NULL) {
+        pr_err("create ssp debugfs error!\n");
+        return -ENOENT;
+    } else if (ssp_dump_reg == ERR_PTR(-ENODEV)) {
+        pr_err("CONFIG_DEBUG_FS is not enabled!\n");
+        return -ENOENT;
+    }
+
+    return 0;
+}
+
+static void ssp_dump_debugfs_remove(void)
+{
+    if (NULL != ssp_dump_reg){
+        debugfs_remove_recursive(ssp_dump_reg);
+    }
+
+    return;
+}
+
+/* ssp_ctrl */
+struct dentry *ssp_ctrl = NULL;
+
+static ssize_t ssp_ctrl_read(struct file *file, char __user *user_buf,
+        size_t count, loff_t *ppos)
+{
+
+    printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
+
+    return 0;
+}
+
+/*
+ *control command:
+ *:   echo 1 > /sys/kernel/debug/ssp_ctrl
+ *:   echo 2 > /sys/kernel/debug/ssp_ctrl
+ *
+ *:   echo 3 > /sys/kernel/debug/ssp_ctrl
+ *:   echo 4 > /sys/kernel/debug/ssp_ctrl
+ *
+ *:   echo 5 > /sys/kernel/debug/ssp_ctrl
+ *:   echo 6 > /sys/kernel/debug/ssp_ctrl
+ */
+static char msg[10];
+void init_ssp_i2s_addr(void);
+
+static ssize_t ssp_ctrl_write(struct file *file,
+        const char __user *user_buf,
+        size_t count, loff_t *ppos)
+{
+    int ret = 0;
+    size_t tmp_count = 0;
+    int rate;
+
+    printk(KERN_INFO"%s/L%d.\n", __FUNCTION__, __LINE__);
+
+    memset(msg, 0x00, sizeof(msg));
+    tmp_count = count;
+
+    if (tmp_count >= sizeof(msg)){
+        tmp_count = sizeof(msg) - 1;
+    }
+
+    /* copy the content from user space to kernel space */
+    ret = copy_from_user(msg, user_buf, tmp_count);
+    if (ret){
+        printk(KERN_ALERT"copy from user fail \n");
+        return -EFAULT;
+    }
+
+    switch (msg[0]){
+        case '0':/* input command# echo 0 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+
+            rate = clk_get_rate(g_ssp->clk);
+
+            clk_set_rate(g_ssp->clk, 6500000);
+
+            rate = clk_get_rate(g_ssp->clk);
+#if 0
+            UI_read_ISCCR2();
+            UI_read_APBC_SSP1_CLK_RST();
+#endif
+            break;
+
+        case '1':/* input command# echo 1 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+
+            rate = clk_get_rate(g_ssp->clk);
+
+            UI_read_SSP_regs();
+
+            //test_ssp1();
+#if 0
+            UI_config_APBC_SSP1_CLK_RST();
+            UI_init_SSP_clk();
+            UI_config_SSP_BCLK(g_gssp_bclk_type, Audio_WB_AMR_Enable);
+            UI_config_SSP_I2S_format();
+#endif
+            break;
+
+        case '2':/* input command# echo 2 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+
+            UI_switch_SSP_role();
+            break;
+
+        case '3':/* input command# echo 3 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+
+            break;
+
+        case '4':/* input command# echo 4 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+
+            UI_Reverse_WBNB();
+            break;
+
+        case '5':/* input command# echo 5 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+
+            UI_switch_bitclk_FS();
+            break;
+
+        case '6':/* input command# echo 6 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_enable_clk(g_ssp);
+            break;
+
+        case '7':/* input command# echo 7 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_disable_clk(g_ssp);
+            break;
+
+        case '8':/* input command# echo 8 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_enable_ssp(g_ssp);
+            break;
+
+        case '9':/* input command# echo 9 > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_disable_ssp(g_ssp);
+            break;
+
+        case 'a':/* input command# echo a > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_switch_frame_bits();
+            break;
+
+        case 'b':/* input command# echo b > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_enable_switch_frame_bits();
+            break;
+
+        case 'c':/* input command# echo c > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_switch_IFS();
+            break;
+
+        case 'd':/* input command# echo d > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_switch_SFRMP();
+            break;
+
+        case 'e':/* input command# echo e > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_switch_SCMODE();
+            break;
+
+        case 'f':/* input command# echo f > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_switch_debug_tools();
+            break;
+
+        case 'g':/* input command# echo g > /sys/kernel/debug/ssp_ctrl */
+            printk(KERN_INFO "input %c. \n", msg[0]);
+            UI_display_global_ctrl_var();
+            break;
+
+        default:/* input command#  */
+            printk(KERN_INFO "input invalid. \n");
+            break;
+    }
+
+    return tmp_count;
+}
+
+static const struct file_operations ssp_ctrl_ops = {
+    .owner      = THIS_MODULE,
+    .open       = simple_open,
+    .read       = ssp_ctrl_read,
+    .write      = ssp_ctrl_write,
+};
+
+static inline int ssp_ctrl_debugfs_init(void)
+{
+
+    ssp_ctrl = debugfs_create_file("ssp_ctrl", S_IRUGO | S_IFREG,
+            NULL, NULL, &ssp_ctrl_ops);
+
+    if (ssp_ctrl == NULL) {
+        pr_err("create ssp_ctrl debugfs error!\n");
+        return -ENOENT;
+    } else if (ssp_ctrl == ERR_PTR(-ENODEV)) {
+        pr_err("CONFIG_DEBUG_FS is not enabled!\n");
+        return -ENOENT;
+    }
+
+    return 0;
+}
+
+static void ssp_ctrl_debugfs_remove(void)
+{
+    if (NULL != ssp_ctrl){
+        debugfs_remove_recursive(ssp_ctrl);
+    }
+
+    return;
+}
+
+void init_ssp_i2s_addr(void)
+{
+    /* APBC_SSP1_CLK_RST */
+#if 0
+    if (!request_mem_region(APBC_SSP1_CLK_RST_ADDR, 4, "APBC_SSP1_CLK_RST_REG")) {
+        printk(KERN_INFO"%s:L%d, error request_mem_region\n", __FUNCTION__, __LINE__);
+        return;
+    }
+#endif
+
+    APBC_SSP1_CLK_RST_reg = ioremap_nocache(APBC_SSP1_CLK_RST_ADDR, 4);
+    if (APBC_SSP1_CLK_RST_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    /* PMU_SQU_CLK_GATE_CTRL */
+#if 0
+    if (!request_mem_region(PMU_SQU_CLK_GATE_CTRL_ADDR, 4, "PMU_SQU_CLK_GATE_CTRL_REG")) {
+        printk(KERN_INFO"%s:L%d, error request_mem_region\n", __FUNCTION__, __LINE__);
+        return;
+    }
+#endif
+
+    PMU_SQU_CLK_GATE_CTRL_reg = ioremap_nocache(PMU_SQU_CLK_GATE_CTRL_ADDR, 4);
+    if (PMU_SQU_CLK_GATE_CTRL_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    /* SQU_CTRL_0 */
+#if 0
+    if (!request_mem_region(SQU_CTRL_0_ADDR, 4, "SQU_CTRL_0_REG")) {
+        printk(KERN_INFO"%s:L%d, error request_mem_region\n", __FUNCTION__, __LINE__);
+        return;
+    }
+#endif
+
+    SQU_CTRL_0_reg = ioremap_nocache(SQU_CTRL_0_ADDR, 4);
+    if (SQU_CTRL_0_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    /* FCCR */
+#if 0
+    if (!request_mem_region(FCCR_ADDR, 4, "FCCR_REG")) {
+        printk(KERN_INFO"%s:L%d, error request_mem_region\n", __FUNCTION__, __LINE__);
+        return;
+    }
+#endif
+
+    FCCR_reg = ioremap_nocache(FCCR_ADDR, 4);
+    if ( FCCR_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    /* ISCCR2 */
+#if 0
+    if (!request_mem_region(ISCCR2_ADDR, 4, "ISCCR2_REG")) {
+        printk(KERN_INFO"%s:L%d, error request_mem_region\n", __FUNCTION__, __LINE__);
+        return;
+    }
+#endif
+
+    ISCCR2_reg = ioremap_nocache(ISCCR2_ADDR, 4);
+    if ( ISCCR2_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    /* ICU_DMA_SEAGULL_INT_STATUS */
+    ICU_DMA_SEAGULL_INT_STATUS_reg = ioremap_nocache(ICU_DMA_SEAGULL_INT_STATUS_ADDR, 4);
+    if ( ICU_DMA_SEAGULL_INT_STATUS_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    /* DMA_BASE */
+    DMA_BASE_reg = ioremap_nocache(DMA_BASE_ADDR, 0x304);
+    if ( DMA_BASE_reg == NULL) {
+        printk(KERN_INFO"%s:L%d, error ioremap\n", __FUNCTION__, __LINE__);
+        return;
+    }
+
+    return;
+}
+
+static void free_ssp_i2s_clk(void)
+{
+    /* APBC_SSP1_CLK_RST */
+    iounmap(APBC_SSP1_CLK_RST_reg);
+    //release_mem_region(APBC_SSP1_CLK_RST_ADDR, 4);
+
+    /* PMU_SQU_CLK_GATE_CTRL */
+    iounmap(PMU_SQU_CLK_GATE_CTRL_reg);
+    //release_mem_region(PMU_SQU_CLK_GATE_CTRL_ADDR, 4);
+
+    /* SQU_CTRL_0 */
+    iounmap(SQU_CTRL_0_reg);
+    //release_mem_region(SQU_CTRL_0_ADDR, 4);
+
+    /* FCCR */
+    iounmap(FCCR_reg);
+    //release_mem_region(FCCR_ADDR, 4);
+
+    /* ISCCR2 */
+    iounmap(ISCCR2_reg);
+    //release_mem_region(ISCCR2_ADDR, 4);
+
+    /* ICU_DMA_SEAGULL_INT_STATUS */
+    iounmap(ICU_DMA_SEAGULL_INT_STATUS_reg);
+
+    /* DMA_BASE */
+    iounmap(DMA_BASE_reg);
+
+    return;
+}
+
+static int pxa_ssp_probe(struct snd_soc_dai *dai)
+{
+	struct device *dev = dai->dev;
+	struct ssp_priv *priv;
+	struct mmp_audio_sspdata *pdata;
+	int ret;
+
+	priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	if (dev->of_node) {
+		struct device_node *ssp_handle;
+
+		ssp_handle = of_parse_phandle(dev->of_node, "port", 0);
+		if (!ssp_handle) {
+			dev_err(dev, "unable to get 'port' phandle\n");
+			ret = -ENODEV;
+			goto err_priv;
+		}
+
+		priv->ssp = pxa_ssp_request_of(ssp_handle, "SoC audio");
+		if (priv->ssp == NULL) {
+			ret = -ENODEV;
+			goto err_priv;
+		}
+
+		of_property_read_u32(dev->of_node, "burst_size",
+				     &priv->burst_size);
+	} else {
+
+		priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
+		if (priv->ssp == NULL) {
+			ret = -ENODEV;
+			goto err_priv;
+		}
+
+		pdata = dev_get_platdata(dai->dev);
+		priv->burst_size = 4;
+	}
+	priv->burst_size = 4;
+
+	/*
+	 * FixMe: for port 5 (gssp), it is shared by ap
+	 * and cp. When AP want to handle it, AP need to
+	 * configure APB to connect gssp. Also reset gssp
+	 * clk to clear the potential impact from cp
+	 */
+	if (priv->ssp->port_id == 5) {
+		priv->apbcp_base = devm_ioremap(dev, APBCONTROL_BASE,
+						APBCONTROL_SIZE);
+		if (priv->apbcp_base == NULL) {
+			dev_err(dev, "failed to ioremap() registers\n");
+			ret = -ENODEV;
+			goto err_priv;
+		}
+	}
+
+	priv->pinctrl = devm_pinctrl_get(dev);
+	if (IS_ERR(priv->pinctrl)) {
+		ret = PTR_ERR(priv->pinctrl);
+		goto err_priv;
+	}
+	priv->pin_ssp = pinctrl_lookup_state(priv->pinctrl, "ssp");
+	if (IS_ERR(priv->pin_ssp)) {
+		dev_err(dev, "could not get ssp pinstate\n");
+		ret = IS_ERR(priv->pin_ssp);
+		goto err_priv;
+	}
+
+	priv->pin_gpio = pinctrl_lookup_state(priv->pinctrl, "default");
+	if (IS_ERR(priv->pin_gpio)) {
+		dev_err(dev, "could not get default(gpio) pinstate\n");
+		ret = IS_ERR(priv->pin_gpio);
+		goto err_priv;
+	}
+
+	ret = pinctrl_select_state(priv->pinctrl, priv->pin_ssp);
+	if (ret) {
+		printk(KERN_INFO"could not set ssp pins\n");
+		goto err_priv;
+	}
+
+	priv->dai_fmt = (unsigned int) -1;
+	snd_soc_dai_set_drvdata(dai, priv);
+	priv->usr_cnt = 0;
+	priv->mfp_init = false;
+
+	/* clear gssp init clock status */
+	clk_prepare_enable(priv->ssp->clk);
+	clk_disable_unprepare(priv->ssp->clk);
+
+    /* init the global variable */
+    g_ssp = priv->ssp;
+
+    /* init debug tool */
+    ssp_dump_debugfs_init();
+    ssp_ctrl_debugfs_init();
+
+    /* init register address */
+    init_ssp_i2s_addr();
+
+    return 0;
+
+err_priv:
+	kfree(priv);
+	return ret;
+}
+
+static int pxa_ssp_remove(struct snd_soc_dai *dai)
+{
+	struct ssp_priv *priv = snd_soc_dai_get_drvdata(dai);
+
+	pxa_ssp_free(priv->ssp);
+	kfree(priv);
+
+	//free debug tool
+	ssp_dump_debugfs_remove();
+	ssp_ctrl_debugfs_remove();
+	free_ssp_i2s_clk();
+
+	return 0;
+}
+
+#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+			  SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |	\
+			  SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |	\
+			  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |	\
+			  SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+			    SNDRV_PCM_FMTBIT_S24_LE |	\
+			    SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+	.startup	= pxa_ssp_startup,
+	.shutdown	= pxa_ssp_shutdown,
+	.trigger	= pxa_ssp_trigger,
+	.hw_params	= pxa_ssp_hw_params,
+	.set_sysclk	= pxa_ssp_set_dai_sysclk,
+	.set_clkdiv	= pxa_ssp_set_dai_clkdiv,
+	.set_pll	= pxa_ssp_set_dai_pll,
+	.set_fmt	= pxa_ssp_set_dai_fmt,
+	.set_tdm_slot	= pxa_ssp_set_dai_tdm_slot,
+	.set_tristate	= pxa_ssp_set_dai_tristate,
+};
+
+static struct snd_soc_dai_driver pxa_ssp_dai = {
+		.probe = pxa_ssp_probe,
+		.remove = pxa_ssp_remove,
+		.suspend = pxa_ssp_suspend,
+		.resume = pxa_ssp_resume,
+		.playback = {
+			.channels_min = 1,
+			.channels_max = 8,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		},
+		.capture = {
+			 .channels_min = 1,
+			 .channels_max = 8,
+			.rates = PXA_SSP_RATES,
+			.formats = PXA_SSP_FORMATS,
+		 },
+		.ops = &pxa_ssp_dai_ops,
+};
+
+static const struct snd_soc_component_driver pxa_ssp_component = {
+	.name		= "pxa-ssp",
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ssp_of_ids[] = {
+	{ .compatible = "asr,pxa-ssp-dai" },
+};
+#endif
+
+static int asoc_ssp_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	char const *platform_driver_name;
+	int ret;
+
+	if (of_property_read_string(np,
+				"platform_driver_name",
+				&platform_driver_name)) {
+		dev_err(&pdev->dev,
+			"Missing platform_driver_name property in the DT\n");
+		return -EINVAL;
+	}
+
+	ret = snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
+					  &pxa_ssp_dai, 1);
+	if (ret != 0) {
+		dev_err(&pdev->dev, "Failed to register DAI\n");
+		return ret;
+	}
+
+	if (strcmp(platform_driver_name, "tdma_platform") == 0) {
+		//ret = mmp_pcm_platform_register(&pdev->dev);
+		/* add ssp_mfp sysfs entries */
+		ret = device_create_file(&pdev->dev, &dev_attr_ssp_mfp);
+		if (ret < 0)
+			dev_err(&pdev->dev,
+				"%s: failed to add ssp_mfp sysfs files: %d\n",
+				__func__, ret);
+	} else if (strcmp(platform_driver_name, "pdma_platform") == 0) {
+		ret = pxa_pcm_platform_register(&pdev->dev);
+		/* add gssp_mfp sysfs entries */
+		ret = device_create_file(&pdev->dev, &dev_attr_gssp_mfp);
+		if (ret < 0)
+			dev_err(&pdev->dev,
+				"%s: failed to add gssp_mfp sysfs files: %d\n",
+				__func__, ret);
+	}
+
+	return ret;
+}
+
+static int asoc_ssp_remove(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	char const *platform_driver_name;
+
+	if (of_property_read_string(np,
+				"platform_driver_name",
+				&platform_driver_name)) {
+		dev_err(&pdev->dev,
+			"Missing platform_driver_name property in the DT\n");
+		return -EINVAL;
+	}
+
+	if (strcmp(platform_driver_name, "tdma_platform") == 0) {
+		device_remove_file(&pdev->dev, &dev_attr_ssp_mfp);
+		//mmp_pcm_platform_unregister(&pdev->dev);
+	} else if (strcmp(platform_driver_name, "pdma_platform") == 0) {
+		device_remove_file(&pdev->dev, &dev_attr_gssp_mfp);
+		snd_soc_unregister_component(&pdev->dev);
+	}
+
+	return 0;
+}
+
+static struct platform_driver asoc_ssp_driver = {
+	.driver = {
+		.name = "pxa-ssp-dai",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(pxa_ssp_of_ids),
+	},
+
+	.probe = asoc_ssp_probe,
+	.remove = asoc_ssp_remove,
+};
+
+module_platform_driver(asoc_ssp_driver);
+
+/* Module information */
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa-ssp-dai");
diff --git a/marvell/linux/sound/soc/pxa/pxa-ssp.h b/marvell/linux/sound/soc/pxa/pxa-ssp.h
new file mode 100644
index 0000000..fc6b147
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa-ssp.h
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * ASoC PXA SSP port support
+ */
+
+#ifndef _PXA_SSP_H
+#define _PXA_SSP_H
+
+/* pxa DAI SSP IDs */
+#define PXA_DAI_SSP1			0
+#define PXA_DAI_SSP2			1
+#define PXA_DAI_SSP3			2
+#define PXA_DAI_SSP4			3
+
+/* SSP clock sources */
+#define PXA_SSP_CLK_PLL	0
+#define PXA_SSP_CLK_EXT	1
+#define PXA_SSP_CLK_NET	2
+#define PXA_SSP_CLK_AUDIO	3
+#define PXA_SSP_CLK_NET_PLL	4
+
+/* SSP audio dividers */
+#define PXA_SSP_AUDIO_DIV_ACDS		0
+#define PXA_SSP_AUDIO_DIV_SCDB		1
+#define PXA_SSP_DIV_SCR			2
+#define PXA_SSP_AUDIO_DIV_ACPS		3
+
+/* SSP ACDS audio dividers values */
+#define PXA_SSP_CLK_AUDIO_DIV_1		0
+#define PXA_SSP_CLK_AUDIO_DIV_2		1
+#define PXA_SSP_CLK_AUDIO_DIV_4		2
+#define PXA_SSP_CLK_AUDIO_DIV_8		3
+#define PXA_SSP_CLK_AUDIO_DIV_16	4
+#define PXA_SSP_CLK_AUDIO_DIV_32	5
+
+/* SSP divider bypass */
+#define PXA_SSP_CLK_SCDB_4		0
+#define PXA_SSP_CLK_SCDB_1		1
+#define PXA_SSP_CLK_SCDB_8		2
+
+#define PXA_SSP_PLL_OUT  0
+
+#define PXA_SSP_FIFO_DEPTH		16
+
+/*
+ * FixMe: for port 5 (gssp), it is shared by ap
+ * and cp. When AP want to handle it, AP need to
+ * configure APB to connect gssp. Also reset gspp
+ * clk to clear the potential impact from cp
+ */
+#define APBCONTROL_BASE		0xD403B000
+#define APBCONTROL_SIZE		0x3C
+#define APBC_GBS		0xC
+#define APBC_GCER		0x34
+
+#define GSSP_BUS_APB_SEL	0x1
+#define GSSP_CLK_SEL_MASK	0x3
+#define GSSP_CLK_SEL_OFF	0x8
+#define GSSP_CLK_EN	(1 << 0)  /* APB Bus Clock Enable */
+#define GSSP_FNCLK_EN	(1 << 1)  /* Functional Clock Enable */
+#define GSSP_RST	(1 << 2)  /* Reset Generation */
+
+//#define DEBUG_SSP1
+
+int mmp_pcm_platform_register(struct device *dev);
+void mmp_pcm_platform_unregister(struct device *dev);
+int pxa_pcm_platform_register(struct device *dev);
+void pxa_pcm_platform_unregister(struct device *dev);
+
+#endif
diff --git a/marvell/linux/sound/soc/pxa/pxa2xx-ac97.c b/marvell/linux/sound/soc/pxa/pxa2xx-ac97.c
new file mode 100644
index 0000000..bf28187
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa2xx-ac97.c
@@ -0,0 +1,298 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Dec 02, 2004
+ * Copyright:	MontaVista Software Inc.
+ */
+
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/dma/pxa-dma.h>
+
+#include <sound/ac97/controller.h>
+#include <sound/core.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
+
+#include <mach/hardware.h>
+#include <mach/regs-ac97.h>
+#include <mach/audio.h>
+
+static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv)
+{
+	pxa2xx_ac97_try_warm_reset();
+
+	pxa2xx_ac97_finish_reset();
+}
+
+static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv)
+{
+	pxa2xx_ac97_try_cold_reset();
+
+	pxa2xx_ac97_finish_reset();
+}
+
+static int pxa2xx_ac97_read_actrl(struct ac97_controller *adrv, int slot,
+				  unsigned short reg)
+{
+	return pxa2xx_ac97_read(slot, reg);
+}
+
+static int pxa2xx_ac97_write_actrl(struct ac97_controller *adrv, int slot,
+				   unsigned short reg, unsigned short val)
+{
+	return pxa2xx_ac97_write(slot, reg, val);
+}
+
+static struct ac97_controller_ops pxa2xx_ac97_ops = {
+	.read	= pxa2xx_ac97_read_actrl,
+	.write	= pxa2xx_ac97_write_actrl,
+	.warm_reset	= pxa2xx_ac97_warm_reset,
+	.reset	= pxa2xx_ac97_cold_reset,
+};
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {
+	.addr		= __PREG(PCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.chan_name	= "pcm_pcm_stereo_in",
+	.maxburst	= 32,
+};
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {
+	.addr		= __PREG(PCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.chan_name	= "pcm_pcm_stereo_out",
+	.maxburst	= 32,
+};
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {
+	.addr		= __PREG(MODR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_2_BYTES,
+	.chan_name	= "pcm_aux_mono_out",
+	.maxburst	= 16,
+};
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {
+	.addr		= __PREG(MODR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_2_BYTES,
+	.chan_name	= "pcm_aux_mono_in",
+	.maxburst	= 16,
+};
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {
+	.addr		= __PREG(MCDR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_2_BYTES,
+	.chan_name	= "pcm_aux_mic_mono",
+	.maxburst	= 16,
+};
+
+static int pxa2xx_ac97_hifi_startup(struct snd_pcm_substream *substream,
+				    struct snd_soc_dai *cpu_dai)
+{
+	struct snd_dmaengine_dai_dma_data *dma_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &pxa2xx_ac97_pcm_stereo_out;
+	else
+		dma_data = &pxa2xx_ac97_pcm_stereo_in;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+	return 0;
+}
+
+static int pxa2xx_ac97_aux_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *cpu_dai)
+{
+	struct snd_dmaengine_dai_dma_data *dma_data;
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &pxa2xx_ac97_pcm_aux_mono_out;
+	else
+		dma_data = &pxa2xx_ac97_pcm_aux_mono_in;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
+
+	return 0;
+}
+
+static int pxa2xx_ac97_mic_startup(struct snd_pcm_substream *substream,
+				   struct snd_soc_dai *cpu_dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		return -ENODEV;
+	snd_soc_dai_set_dma_data(cpu_dai, substream,
+				 &pxa2xx_ac97_pcm_mic_mono_in);
+
+	return 0;
+}
+
+#define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000)
+
+static const struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {
+	.startup	= pxa2xx_ac97_hifi_startup,
+};
+
+static const struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {
+	.startup	= pxa2xx_ac97_aux_startup,
+};
+
+static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
+	.startup	= pxa2xx_ac97_mic_startup,
+};
+
+/*
+ * There is only 1 physical AC97 interface for pxa2xx, but it
+ * has extra fifo's that can be used for aux DACs and ADCs.
+ */
+static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
+{
+	.name = "pxa2xx-ac97",
+	.bus_control = true,
+	.playback = {
+		.stream_name = "AC97 Playback",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "AC97 Capture",
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &pxa_ac97_hifi_dai_ops,
+},
+{
+	.name = "pxa2xx-ac97-aux",
+	.bus_control = true,
+	.playback = {
+		.stream_name = "AC97 Aux Playback",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.stream_name = "AC97 Aux Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &pxa_ac97_aux_dai_ops,
+},
+{
+	.name = "pxa2xx-ac97-mic",
+	.bus_control = true,
+	.capture = {
+		.stream_name = "AC97 Mic Capture",
+		.channels_min = 1,
+		.channels_max = 1,
+		.rates = PXA2XX_AC97_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &pxa_ac97_mic_dai_ops,
+},
+};
+
+static const struct snd_soc_component_driver pxa_ac97_component = {
+	.name		= "pxa-ac97",
+	.ops		= &pxa2xx_pcm_ops,
+	.pcm_new	= pxa2xx_soc_pcm_new,
+	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pxa2xx_ac97_dt_ids[] = {
+	{ .compatible = "marvell,pxa250-ac97", },
+	{ .compatible = "marvell,pxa270-ac97", },
+	{ .compatible = "marvell,pxa300-ac97", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids);
+
+#endif
+
+static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)
+{
+	int ret;
+	struct ac97_controller *ctrl;
+	pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;
+	void **codecs_pdata;
+
+	if (pdev->id != -1) {
+		dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");
+		return -ENXIO;
+	}
+
+	ret = pxa2xx_ac97_hw_probe(pdev);
+	if (ret) {
+		dev_err(&pdev->dev, "PXA2xx AC97 hw probe error (%d)\n", ret);
+		return ret;
+	}
+
+	codecs_pdata = pdata ? pdata->codec_pdata : NULL;
+	ctrl = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev,
+					    AC97_SLOTS_AVAILABLE_ALL,
+					    codecs_pdata);
+	if (IS_ERR(ctrl))
+		return PTR_ERR(ctrl);
+
+	platform_set_drvdata(pdev, ctrl);
+	/* Punt most of the init to the SoC probe; we may need the machine
+	 * driver to do interesting things with the clocking to get us up
+	 * and running.
+	 */
+	return devm_snd_soc_register_component(&pdev->dev, &pxa_ac97_component,
+					  pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver));
+}
+
+static int pxa2xx_ac97_dev_remove(struct platform_device *pdev)
+{
+	struct ac97_controller *ctrl = platform_get_drvdata(pdev);
+
+	snd_ac97_controller_unregister(ctrl);
+	pxa2xx_ac97_hw_remove(pdev);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int pxa2xx_ac97_dev_suspend(struct device *dev)
+{
+	return pxa2xx_ac97_hw_suspend();
+}
+
+static int pxa2xx_ac97_dev_resume(struct device *dev)
+{
+	return pxa2xx_ac97_hw_resume();
+}
+
+static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,
+		pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume);
+#endif
+
+static struct platform_driver pxa2xx_ac97_driver = {
+	.probe		= pxa2xx_ac97_dev_probe,
+	.remove		= pxa2xx_ac97_dev_remove,
+	.driver		= {
+		.name	= "pxa2xx-ac97",
+#ifdef CONFIG_PM_SLEEP
+		.pm	= &pxa2xx_ac97_pm_ops,
+#endif
+		.of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids),
+	},
+};
+
+module_platform_driver(pxa2xx_ac97_driver);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-ac97");
diff --git a/marvell/linux/sound/soc/pxa/pxa2xx-i2s.c b/marvell/linux/sound/soc/pxa/pxa2xx-i2s.c
new file mode 100644
index 0000000..9f7fb73
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa2xx-i2s.c
@@ -0,0 +1,400 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * pxa2xx-i2s.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         lrg@slimlogic.co.uk
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
+
+#include <mach/hardware.h>
+#include <mach/audio.h>
+
+#include "pxa2xx-i2s.h"
+
+/*
+ * I2S Controller Register and Bit Definitions
+ */
+#define SACR0		__REG(0x40400000)  /* Global Control Register */
+#define SACR1		__REG(0x40400004)  /* Serial Audio I 2 S/MSB-Justified Control Register */
+#define SASR0		__REG(0x4040000C)  /* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
+#define SAIMR		__REG(0x40400014)  /* Serial Audio Interrupt Mask Register */
+#define SAICR		__REG(0x40400018)  /* Serial Audio Interrupt Clear Register */
+#define SADIV		__REG(0x40400060)  /* Audio Clock Divider Register. */
+#define SADR		__REG(0x40400080)  /* Serial Audio Data Register (TX and RX FIFO access Register). */
+
+#define SACR0_RFTH(x)	((x) << 12)	/* Rx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_TFTH(x)	((x) << 8)	/* Tx FIFO Interrupt or DMA Trigger Threshold */
+#define SACR0_STRF	(1 << 5)	/* FIFO Select for EFWR Special Function */
+#define SACR0_EFWR	(1 << 4)	/* Enable EFWR Function  */
+#define SACR0_RST	(1 << 3)	/* FIFO, i2s Register Reset */
+#define SACR0_BCKD	(1 << 2)	/* Bit Clock Direction */
+#define SACR0_ENB	(1 << 0)	/* Enable I2S Link */
+#define SACR1_ENLBF	(1 << 5)	/* Enable Loopback */
+#define SACR1_DRPL	(1 << 4)	/* Disable Replaying Function */
+#define SACR1_DREC	(1 << 3)	/* Disable Recording Function */
+#define SACR1_AMSL	(1 << 0)	/* Specify Alternate Mode */
+
+#define SASR0_I2SOFF	(1 << 7)	/* Controller Status */
+#define SASR0_ROR	(1 << 6)	/* Rx FIFO Overrun */
+#define SASR0_TUR	(1 << 5)	/* Tx FIFO Underrun */
+#define SASR0_RFS	(1 << 4)	/* Rx FIFO Service Request */
+#define SASR0_TFS	(1 << 3)	/* Tx FIFO Service Request */
+#define SASR0_BSY	(1 << 2)	/* I2S Busy */
+#define SASR0_RNE	(1 << 1)	/* Rx FIFO Not Empty */
+#define SASR0_TNF	(1 << 0)	/* Tx FIFO Not Empty */
+
+#define SAICR_ROR	(1 << 6)	/* Clear Rx FIFO Overrun Interrupt */
+#define SAICR_TUR	(1 << 5)	/* Clear Tx FIFO Underrun Interrupt */
+
+#define SAIMR_ROR	(1 << 6)	/* Enable Rx FIFO Overrun Condition Interrupt */
+#define SAIMR_TUR	(1 << 5)	/* Enable Tx FIFO Underrun Condition Interrupt */
+#define SAIMR_RFS	(1 << 4)	/* Enable Rx FIFO Service Interrupt */
+#define SAIMR_TFS	(1 << 3)	/* Enable Tx FIFO Service Interrupt */
+
+struct pxa_i2s_port {
+	u32 sadiv;
+	u32 sacr0;
+	u32 sacr1;
+	u32 saimr;
+	int master;
+	u32 fmt;
+};
+static struct pxa_i2s_port pxa_i2s;
+static struct clk *clk_i2s;
+static int clk_ena = 0;
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
+	.addr		= __PREG(SADR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.chan_name	= "tx",
+	.maxburst	= 32,
+};
+
+static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
+	.addr		= __PREG(SADR),
+	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
+	.chan_name	= "rx",
+	.maxburst	= 32,
+};
+
+static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+
+	if (IS_ERR(clk_i2s))
+		return PTR_ERR(clk_i2s);
+
+	if (!cpu_dai->active)
+		SACR0 = 0;
+
+	return 0;
+}
+
+/* wait for I2S controller to be ready */
+static int pxa_i2s_wait(void)
+{
+	int i;
+
+	/* flush the Rx FIFO */
+	for (i = 0; i < 16; i++)
+		SADR;
+	return 0;
+}
+
+static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+		unsigned int fmt)
+{
+	/* interface format */
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		pxa_i2s.fmt = 0;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		pxa_i2s.fmt = SACR1_AMSL;
+		break;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		pxa_i2s.master = 1;
+		break;
+	case SND_SOC_DAIFMT_CBM_CFS:
+		pxa_i2s.master = 0;
+		break;
+	default:
+		break;
+	}
+	return 0;
+}
+
+static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+		int clk_id, unsigned int freq, int dir)
+{
+	if (clk_id != PXA2XX_I2S_SYSCLK)
+		return -ENODEV;
+
+	return 0;
+}
+
+static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_dmaengine_dai_dma_data *dma_data;
+
+	if (WARN_ON(IS_ERR(clk_i2s)))
+		return -EINVAL;
+	clk_prepare_enable(clk_i2s);
+	clk_ena = 1;
+	pxa_i2s_wait();
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dma_data = &pxa2xx_i2s_pcm_stereo_out;
+	else
+		dma_data = &pxa2xx_i2s_pcm_stereo_in;
+
+	snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+	/* is port used by another stream */
+	if (!(SACR0 & SACR0_ENB)) {
+		SACR0 = 0;
+		if (pxa_i2s.master)
+			SACR0 |= SACR0_BCKD;
+
+		SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);
+		SACR1 |= pxa_i2s.fmt;
+	}
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		SAIMR |= SAIMR_TFS;
+	else
+		SAIMR |= SAIMR_RFS;
+
+	switch (params_rate(params)) {
+	case 8000:
+		SADIV = 0x48;
+		break;
+	case 11025:
+		SADIV = 0x34;
+		break;
+	case 16000:
+		SADIV = 0x24;
+		break;
+	case 22050:
+		SADIV = 0x1a;
+		break;
+	case 44100:
+		SADIV = 0xd;
+		break;
+	case 48000:
+		SADIV = 0xc;
+		break;
+	case 96000: /* not in manual and possibly slightly inaccurate */
+		SADIV = 0x6;
+		break;
+	}
+
+	return 0;
+}
+
+static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+			      struct snd_soc_dai *dai)
+{
+	int ret = 0;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			SACR1 &= ~SACR1_DRPL;
+		else
+			SACR1 &= ~SACR1_DREC;
+		SACR0 |= SACR0_ENB;
+		break;
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+		SACR1 |= SACR1_DRPL;
+		SAIMR &= ~SAIMR_TFS;
+	} else {
+		SACR1 |= SACR1_DREC;
+		SAIMR &= ~SAIMR_RFS;
+	}
+
+	if ((SACR1 & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
+		SACR0 &= ~SACR0_ENB;
+		pxa_i2s_wait();
+		if (clk_ena) {
+			clk_disable_unprepare(clk_i2s);
+			clk_ena = 0;
+		}
+	}
+}
+
+#ifdef CONFIG_PM
+static int pxa2xx_i2s_suspend(struct snd_soc_dai *dai)
+{
+	/* store registers */
+	pxa_i2s.sacr0 = SACR0;
+	pxa_i2s.sacr1 = SACR1;
+	pxa_i2s.saimr = SAIMR;
+	pxa_i2s.sadiv = SADIV;
+
+	/* deactivate link */
+	SACR0 &= ~SACR0_ENB;
+	pxa_i2s_wait();
+	return 0;
+}
+
+static int pxa2xx_i2s_resume(struct snd_soc_dai *dai)
+{
+	pxa_i2s_wait();
+
+	SACR0 = pxa_i2s.sacr0 & ~SACR0_ENB;
+	SACR1 = pxa_i2s.sacr1;
+	SAIMR = pxa_i2s.saimr;
+	SADIV = pxa_i2s.sadiv;
+
+	SACR0 = pxa_i2s.sacr0;
+
+	return 0;
+}
+
+#else
+#define pxa2xx_i2s_suspend	NULL
+#define pxa2xx_i2s_resume	NULL
+#endif
+
+static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
+{
+	clk_i2s = clk_get(dai->dev, "I2SCLK");
+	if (IS_ERR(clk_i2s))
+		return PTR_ERR(clk_i2s);
+
+	/*
+	 * PXA Developer's Manual:
+	 * If SACR0[ENB] is toggled in the middle of a normal operation,
+	 * the SACR0[RST] bit must also be set and cleared to reset all
+	 * I2S controller registers.
+	 */
+	SACR0 = SACR0_RST;
+	SACR0 = 0;
+	/* Make sure RPL and REC are disabled */
+	SACR1 = SACR1_DRPL | SACR1_DREC;
+	/* Along with FIFO servicing */
+	SAIMR &= ~(SAIMR_RFS | SAIMR_TFS);
+
+	snd_soc_dai_init_dma_data(dai, &pxa2xx_i2s_pcm_stereo_out,
+		&pxa2xx_i2s_pcm_stereo_in);
+
+	return 0;
+}
+
+static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
+{
+	clk_put(clk_i2s);
+	clk_i2s = ERR_PTR(-ENOENT);
+	return 0;
+}
+
+#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
+		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
+
+static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
+	.startup	= pxa2xx_i2s_startup,
+	.shutdown	= pxa2xx_i2s_shutdown,
+	.trigger	= pxa2xx_i2s_trigger,
+	.hw_params	= pxa2xx_i2s_hw_params,
+	.set_fmt	= pxa2xx_i2s_set_dai_fmt,
+	.set_sysclk	= pxa2xx_i2s_set_dai_sysclk,
+};
+
+static struct snd_soc_dai_driver pxa_i2s_dai = {
+	.probe = pxa2xx_i2s_probe,
+	.remove = pxa2xx_i2s_remove,
+	.suspend = pxa2xx_i2s_suspend,
+	.resume = pxa2xx_i2s_resume,
+	.playback = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_I2S_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.capture = {
+		.channels_min = 2,
+		.channels_max = 2,
+		.rates = PXA2XX_I2S_RATES,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
+	.ops = &pxa_i2s_dai_ops,
+	.symmetric_rates = 1,
+};
+
+static const struct snd_soc_component_driver pxa_i2s_component = {
+	.name		= "pxa-i2s",
+	.ops		= &pxa2xx_pcm_ops,
+	.pcm_new	= pxa2xx_soc_pcm_new,
+	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
+};
+
+static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
+					       &pxa_i2s_dai, 1);
+}
+
+static struct platform_driver pxa2xx_i2s_driver = {
+	.probe = pxa2xx_i2s_drv_probe,
+
+	.driver = {
+		.name = "pxa2xx-i2s",
+	},
+};
+
+static int __init pxa2xx_i2s_init(void)
+{
+	clk_i2s = ERR_PTR(-ENOENT);
+	return platform_driver_register(&pxa2xx_i2s_driver);
+}
+
+static void __exit pxa2xx_i2s_exit(void)
+{
+	platform_driver_unregister(&pxa2xx_i2s_driver);
+}
+
+module_init(pxa2xx_i2s_init);
+module_exit(pxa2xx_i2s_exit);
+
+/* Module information */
+MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
+MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa2xx-i2s");
diff --git a/marvell/linux/sound/soc/pxa/pxa2xx-i2s.h b/marvell/linux/sound/soc/pxa/pxa2xx-i2s.h
new file mode 100644
index 0000000..263568d
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa2xx-i2s.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * linux/sound/soc/pxa/pxa2xx-i2s.h
+ */
+
+#ifndef _PXA2XX_I2S_H
+#define _PXA2XX_I2S_H
+
+/* I2S clock */
+#define PXA2XX_I2S_SYSCLK		0
+
+#endif
diff --git a/marvell/linux/sound/soc/pxa/pxa2xx-pcm.c b/marvell/linux/sound/soc/pxa/pxa2xx-pcm.c
new file mode 100644
index 0000000..74b56fa
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/pxa2xx-pcm.c
@@ -0,0 +1,45 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
+ *
+ * Author:	Nicolas Pitre
+ * Created:	Nov 30, 2004
+ * Copyright:	(C) 2004 MontaVista Software, Inc.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/of.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
+
+static const struct snd_soc_component_driver pxa2xx_soc_platform = {
+	.ops		= &pxa2xx_pcm_ops,
+	.pcm_new	= pxa2xx_soc_pcm_new,
+	.pcm_free	= pxa2xx_pcm_free_dma_buffers,
+};
+
+static int pxa2xx_soc_platform_probe(struct platform_device *pdev)
+{
+	return devm_snd_soc_register_component(&pdev->dev, &pxa2xx_soc_platform,
+					       NULL, 0);
+}
+
+static struct platform_driver pxa_pcm_driver = {
+	.driver = {
+		.name = "pxa-pcm-audio",
+	},
+
+	.probe = pxa2xx_soc_platform_probe,
+};
+
+module_platform_driver(pxa_pcm_driver);
+
+MODULE_AUTHOR("Nicolas Pitre");
+MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pxa-pcm-audio");
diff --git a/marvell/linux/sound/soc/pxa/spitz.c b/marvell/linux/sound/soc/pxa/spitz.c
new file mode 100644
index 0000000..f7babff
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/spitz.c
@@ -0,0 +1,340 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * spitz.c  --  SoC audio for Sharp SL-Cxx00 models Spitz, Borzoi and Akita
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *          Richard Purdie <richard@openedhand.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/spitz.h>
+#include "../codecs/wm8750.h"
+#include "pxa2xx-i2s.h"
+
+#define SPITZ_HP        0
+#define SPITZ_MIC       1
+#define SPITZ_LINE      2
+#define SPITZ_HEADSET   3
+#define SPITZ_HP_OFF    4
+#define SPITZ_SPK_ON    0
+#define SPITZ_SPK_OFF   1
+
+ /* audio clock in Hz - rounded from 12.235MHz */
+#define SPITZ_AUDIO_CLOCK 12288000
+
+static int spitz_jack_func;
+static int spitz_spk_func;
+static int spitz_mic_gpio;
+
+static void spitz_ext_control(struct snd_soc_dapm_context *dapm)
+{
+	snd_soc_dapm_mutex_lock(dapm);
+
+	if (spitz_spk_func == SPITZ_SPK_ON)
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk");
+	else
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk");
+
+	/* set up jack connection */
+	switch (spitz_jack_func) {
+	case SPITZ_HP:
+		/* enable and unmute hp jack, disable mic bias */
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 1);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
+		break;
+	case SPITZ_MIC:
+		/* enable mic jack and bias, mute hp */
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
+		break;
+	case SPITZ_LINE:
+		/* enable line jack, disable mic bias and mute hp */
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack");
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
+		break;
+	case SPITZ_HEADSET:
+		/* enable and unmute headset jack enable mic bias, mute L hp */
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 1);
+		break;
+	case SPITZ_HP_OFF:
+
+		/* jack removed, everything off */
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack");
+		gpio_set_value(SPITZ_GPIO_MUTE_L, 0);
+		gpio_set_value(SPITZ_GPIO_MUTE_R, 0);
+		break;
+	}
+
+	snd_soc_dapm_sync_unlocked(dapm);
+
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static int spitz_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* check the jack status at stream startup */
+	spitz_ext_control(&rtd->card->dapm);
+
+	return 0;
+}
+
+static int spitz_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_ops spitz_ops = {
+	.startup = spitz_startup,
+	.hw_params = spitz_hw_params,
+};
+
+static int spitz_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = spitz_jack_func;
+	return 0;
+}
+
+static int spitz_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (spitz_jack_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	spitz_jack_func = ucontrol->value.enumerated.item[0];
+	spitz_ext_control(&card->dapm);
+	return 1;
+}
+
+static int spitz_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = spitz_spk_func;
+	return 0;
+}
+
+static int spitz_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (spitz_spk_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	spitz_spk_func = ucontrol->value.enumerated.item[0];
+	spitz_ext_control(&card->dapm);
+	return 1;
+}
+
+static int spitz_mic_bias(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	gpio_set_value_cansleep(spitz_mic_gpio, SND_SOC_DAPM_EVENT_ON(event));
+	return 0;
+}
+
+/* spitz machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", spitz_mic_bias),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+	SND_SOC_DAPM_LINE("Line Jack", NULL),
+
+	/* headset is a mic and mono headphone */
+	SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Spitz machine audio_map */
+static const struct snd_soc_dapm_route spitz_audio_map[] = {
+
+	/* headphone connected to LOUT1, ROUT1 */
+	{"Headphone Jack", NULL, "LOUT1"},
+	{"Headphone Jack", NULL, "ROUT1"},
+
+	/* headset connected to ROUT1 and LINPUT1 with bias (def below) */
+	{"Headset Jack", NULL, "ROUT1"},
+
+	/* ext speaker connected to LOUT2, ROUT2  */
+	{"Ext Spk", NULL, "ROUT2"},
+	{"Ext Spk", NULL, "LOUT2"},
+
+	/* mic is connected to input 1 - with bias */
+	{"LINPUT1", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic Jack"},
+
+	/* line is connected to input 1 - no bias */
+	{"LINPUT1", NULL, "Line Jack"},
+};
+
+static const char * const jack_function[] = {"Headphone", "Mic", "Line",
+	"Headset", "Off"};
+static const char * const spk_function[] = {"On", "Off"};
+static const struct soc_enum spitz_enum[] = {
+	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new wm8750_spitz_controls[] = {
+	SOC_ENUM_EXT("Jack Function", spitz_enum[0], spitz_get_jack,
+		spitz_set_jack),
+	SOC_ENUM_EXT("Speaker Function", spitz_enum[1], spitz_get_spk,
+		spitz_set_spk),
+};
+
+/* spitz digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(wm8750,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link spitz_dai = {
+	.name = "wm8750",
+	.stream_name = "WM8750",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+	.ops = &spitz_ops,
+	SND_SOC_DAILINK_REG(wm8750),
+};
+
+/* spitz audio machine driver */
+static struct snd_soc_card snd_soc_spitz = {
+	.name = "Spitz",
+	.owner = THIS_MODULE,
+	.dai_link = &spitz_dai,
+	.num_links = 1,
+
+	.controls = wm8750_spitz_controls,
+	.num_controls = ARRAY_SIZE(wm8750_spitz_controls),
+	.dapm_widgets = wm8750_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+	.dapm_routes = spitz_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
+	.fully_routed = true,
+};
+
+static int spitz_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &snd_soc_spitz;
+	int ret;
+
+	if (machine_is_akita())
+		spitz_mic_gpio = AKITA_GPIO_MIC_BIAS;
+	else
+		spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
+
+	ret = gpio_request(spitz_mic_gpio, "MIC GPIO");
+	if (ret)
+		goto err1;
+
+	ret = gpio_direction_output(spitz_mic_gpio, 0);
+	if (ret)
+		goto err2;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		goto err2;
+	}
+
+	return 0;
+
+err2:
+	gpio_free(spitz_mic_gpio);
+err1:
+	return ret;
+}
+
+static int spitz_remove(struct platform_device *pdev)
+{
+	gpio_free(spitz_mic_gpio);
+	return 0;
+}
+
+static struct platform_driver spitz_driver = {
+	.driver		= {
+		.name	= "spitz-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= spitz_probe,
+	.remove		= spitz_remove,
+};
+
+module_platform_driver(spitz_driver);
+
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Spitz");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spitz-audio");
diff --git a/marvell/linux/sound/soc/pxa/ssp-dummy.c b/marvell/linux/sound/soc/pxa/ssp-dummy.c
new file mode 100644
index 0000000..b957901
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/ssp-dummy.c
@@ -0,0 +1,280 @@
+/*
+ * pxa-ssp.c  --  ALSA Soc Audio Layer
+ *
+ * Copyright 2005,2008 Wolfson Microelectronics PLC.
+ * Author: Liam Girdwood
+ *         Mark Brown <broonie@opensource.wolfsonmicro.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ * TODO:
+ *  o Test network mode for > 16bit sample size
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/pxa2xx_ssp.h>
+#include <linux/of.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/platform_data/mmp_audio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+#include <linux/features.h>
+
+#include <asm/irq.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/pxa2xx-lib.h>
+#include <sound/dmaengine_pcm.h>
+
+//#include <mach/hardware.h>
+
+//#include "../../arm/pxa2xx-pcm.h"
+#include "pxa-ssp.h"
+#ifndef CONFIG_CPU_ASR18XX
+extern u32 sscr0_hifi;
+extern u32 sscr1_hifi;
+#else
+extern u32 top_ctrl_hifi;
+extern u32 fifo_ctrl_hifi;
+extern u32 rwot_ctrl_hifi;
+extern u32 network_ctrl_hifi;
+extern u32 int_en_hifi;
+#endif
+
+//extern int mmp_pcm_probe(struct platform_device *pdev);
+//extern int pxa_pcm_platform_register(struct device *dev);
+
+static int pxa_ssp_startup(struct snd_pcm_substream *substream,
+        struct snd_soc_dai *cpu_dai)
+{
+    return 0;
+}
+
+static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
+        struct snd_soc_dai *cpu_dai)
+{
+    return;
+}
+
+#ifdef CONFIG_PM
+
+static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
+{
+    return 0;
+}
+
+static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
+{
+    return 0;
+}
+
+#else
+#define pxa_ssp_suspend	NULL
+#define pxa_ssp_resume	NULL
+#endif
+
+
+/*
+ * Set the SSP ports SYSCLK.
+ */
+static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
+        int clk_id, unsigned int freq, int dir)
+{
+    return 0;
+}
+
+/*
+ * Set the SSP clock dividers.
+ */
+static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
+        int div_id, int div)
+{
+    return 0;
+}
+
+/*
+ * Configure the PLL frequency pxa27x and (afaik - pxa320 only)
+ */
+static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
+        int source, unsigned int freq_in, unsigned int freq_out)
+{
+    return 0;
+}
+
+/*
+ * Set the active slots in TDM/Network mode
+ */
+static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
+        unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
+{
+    return 0;
+}
+
+/*
+ * Tristate the SSP DAI lines
+ */
+static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
+        int tristate)
+{
+    return 0;
+}
+
+/*
+ * Set up the SSP DAI format.
+ * The SSP Port must be inactive before calling this function as the
+ * physical interface format is changed.
+ */
+static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+        unsigned int fmt)
+{
+    return 0;
+}
+
+/*
+ * Set the SSP audio DMA parameters and sample size.
+ * Can be called multiple times by oss emulation.
+ */
+
+static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
+        struct snd_pcm_hw_params *params,
+        struct snd_soc_dai *cpu_dai)
+{
+    return 0;
+}
+
+static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
+        struct snd_soc_dai *cpu_dai)
+{
+    return 0;
+}
+
+static int pxa_ssp_probe(struct snd_soc_dai *dai)
+{
+    return 0;
+}
+
+static int pxa_ssp_remove(struct snd_soc_dai *dai)
+{
+    return 0;
+}
+
+#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
+        SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |	\
+        SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |	\
+        SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |	\
+        SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
+        SNDRV_PCM_FMTBIT_S24_LE |	\
+        SNDRV_PCM_FMTBIT_S32_LE)
+
+static const struct snd_soc_dai_ops pxa_ssp_dai_ops = {
+    .startup	= pxa_ssp_startup,
+    .shutdown	= pxa_ssp_shutdown,
+    .trigger	= pxa_ssp_trigger,
+    .hw_params	= pxa_ssp_hw_params,
+    .set_sysclk	= pxa_ssp_set_dai_sysclk,
+    .set_clkdiv	= pxa_ssp_set_dai_clkdiv,
+    .set_pll	= pxa_ssp_set_dai_pll,
+    .set_fmt	= pxa_ssp_set_dai_fmt,
+    .set_tdm_slot	= pxa_ssp_set_dai_tdm_slot,
+    .set_tristate	= pxa_ssp_set_dai_tristate,
+};
+
+static struct snd_soc_dai_driver pxa_ssp_dai = {
+    .probe = pxa_ssp_probe,
+    .remove = pxa_ssp_remove,
+    .suspend = pxa_ssp_suspend,
+    .resume = pxa_ssp_resume,
+    .playback = {
+        .channels_min = 1,
+        .channels_max = 8,
+        .rates = PXA_SSP_RATES,
+        .formats = PXA_SSP_FORMATS,
+    },
+    .capture = {
+        .channels_min = 1,
+        .channels_max = 8,
+        .rates = PXA_SSP_RATES,
+        .formats = PXA_SSP_FORMATS,
+    },
+    .ops = &pxa_ssp_dai_ops,
+};
+
+static const struct snd_soc_component_driver pxa_ssp_component = {
+    .name		= "pxa-ssp",
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id pxa_ssp_of_ids[] = {
+    { .compatible = "asr,pxa-ssp-dai" },
+};
+#endif
+
+static int asoc_ssp_probe(struct platform_device *pdev)
+{
+    struct device_node *np = pdev->dev.of_node;
+    char const *platform_driver_name;
+    int ret;
+
+    printk(KERN_INFO"[5616 platform probe: begin] %s/L%d.\n", __FUNCTION__, __LINE__);
+
+    if (of_property_read_string(np,
+                "platform_driver_name",
+                &platform_driver_name)) {
+        dev_err(&pdev->dev,
+                "Missing platform_driver_name property in the DT\n");
+        return -EINVAL;
+    }
+
+    ret = devm_snd_soc_register_component(&pdev->dev, &pxa_ssp_component,
+            &pxa_ssp_dai, 1);
+    if (ret != 0) {
+        dev_err(&pdev->dev, "Failed to register DAI\n");
+        return ret;
+    }
+
+#if 0 //yjg
+    if (strcmp(platform_driver_name, "tdma_platform") == 0) {
+        printk(KERN_INFO"[5616 platform probe] %s/L%d.\n", __FUNCTION__, __LINE__);
+        ret = mmp_pcm_probe(pdev);
+    } else if (strcmp(platform_driver_name, "pdma_platform") == 0) {
+        printk(KERN_INFO"[5616 platform probe] %s/L%d.\n", __FUNCTION__, __LINE__);
+        ret = pxa_pcm_platform_register(&pdev->dev);
+    }
+#endif
+
+    printk(KERN_INFO"[5616 platform probe: end] %s/L%d.\n", __FUNCTION__, __LINE__);
+
+    return ret;
+}
+
+static struct platform_driver asoc_ssp_driver = {
+    .driver = {
+        .name = "pxa-ssp-dai",
+        .of_match_table = of_match_ptr(pxa_ssp_of_ids),
+    },
+
+    .probe = asoc_ssp_probe,
+    //.remove = asoc_ssp_remove,
+};
+
+module_platform_driver(asoc_ssp_driver);
+
+/* Module information */
+MODULE_AUTHOR("wenchen@asrmicro.com");
+MODULE_DESCRIPTION("ASR SSP/PCM SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/marvell/linux/sound/soc/pxa/tosa.c b/marvell/linux/sound/soc/pxa/tosa.c
new file mode 100644
index 0000000..b429db2
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/tosa.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * tosa.c  --  SoC audio for Tosa
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Authors: Liam Girdwood <lrg@slimlogic.co.uk>
+ *          Richard Purdie <richard@openedhand.com>
+ *
+ * GPIO's
+ *  1 - Jack Insertion
+ *  5 - Hookswitch (headset answer/hang up switch)
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/tosa.h>
+#include <mach/audio.h>
+
+#define TOSA_HP        0
+#define TOSA_MIC_INT   1
+#define TOSA_HEADSET   2
+#define TOSA_HP_OFF    3
+#define TOSA_SPK_ON    0
+#define TOSA_SPK_OFF   1
+
+static int tosa_jack_func;
+static int tosa_spk_func;
+
+static void tosa_ext_control(struct snd_soc_dapm_context *dapm)
+{
+
+	snd_soc_dapm_mutex_lock(dapm);
+
+	/* set up jack connection */
+	switch (tosa_jack_func) {
+	case TOSA_HP:
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	case TOSA_MIC_INT:
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Mic (Internal)");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	case TOSA_HEADSET:
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)");
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack");
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack");
+		break;
+	}
+
+	if (tosa_spk_func == TOSA_SPK_ON)
+		snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker");
+	else
+		snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker");
+
+	snd_soc_dapm_sync_unlocked(dapm);
+
+	snd_soc_dapm_mutex_unlock(dapm);
+}
+
+static int tosa_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+
+	/* check the jack status at stream startup */
+	tosa_ext_control(&rtd->card->dapm);
+
+	return 0;
+}
+
+static const struct snd_soc_ops tosa_ops = {
+	.startup = tosa_startup,
+};
+
+static int tosa_get_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = tosa_jack_func;
+	return 0;
+}
+
+static int tosa_set_jack(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (tosa_jack_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	tosa_jack_func = ucontrol->value.enumerated.item[0];
+	tosa_ext_control(&card->dapm);
+	return 1;
+}
+
+static int tosa_get_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	ucontrol->value.enumerated.item[0] = tosa_spk_func;
+	return 0;
+}
+
+static int tosa_set_spk(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+
+	if (tosa_spk_func == ucontrol->value.enumerated.item[0])
+		return 0;
+
+	tosa_spk_func = ucontrol->value.enumerated.item[0];
+	tosa_ext_control(&card->dapm);
+	return 1;
+}
+
+/* tosa dapm event handlers */
+static int tosa_hp_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *k, int event)
+{
+	gpio_set_value(TOSA_GPIO_L_MUTE, SND_SOC_DAPM_EVENT_ON(event) ? 1 : 0);
+	return 0;
+}
+
+/* tosa machine dapm widgets */
+static const struct snd_soc_dapm_widget tosa_dapm_widgets[] = {
+SND_SOC_DAPM_HP("Headphone Jack", tosa_hp_event),
+SND_SOC_DAPM_HP("Headset Jack", NULL),
+SND_SOC_DAPM_MIC("Mic (Internal)", NULL),
+SND_SOC_DAPM_SPK("Speaker", NULL),
+};
+
+/* tosa audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	/* headphone connected to HPOUTL, HPOUTR */
+	{"Headphone Jack", NULL, "HPOUTL"},
+	{"Headphone Jack", NULL, "HPOUTR"},
+
+	/* ext speaker connected to LOUT2, ROUT2 */
+	{"Speaker", NULL, "LOUT2"},
+	{"Speaker", NULL, "ROUT2"},
+
+	/* internal mic is connected to mic1, mic2 differential - with bias */
+	{"MIC1", NULL, "Mic Bias"},
+	{"MIC2", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic (Internal)"},
+
+	/* headset is connected to HPOUTR, and LINEINR with bias */
+	{"Headset Jack", NULL, "HPOUTR"},
+	{"LINEINR", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Headset Jack"},
+};
+
+static const char * const jack_function[] = {"Headphone", "Mic", "Line",
+	"Headset", "Off"};
+static const char * const spk_function[] = {"On", "Off"};
+static const struct soc_enum tosa_enum[] = {
+	SOC_ENUM_SINGLE_EXT(5, jack_function),
+	SOC_ENUM_SINGLE_EXT(2, spk_function),
+};
+
+static const struct snd_kcontrol_new tosa_controls[] = {
+	SOC_ENUM_EXT("Jack Function", tosa_enum[0], tosa_get_jack,
+		tosa_set_jack),
+	SOC_ENUM_EXT("Speaker Function", tosa_enum[1], tosa_get_spk,
+		tosa_set_spk),
+};
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9712-codec", "wm9712-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link tosa_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.ops = &tosa_ops,
+	SND_SOC_DAILINK_REG(ac97),
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	.ops = &tosa_ops,
+	SND_SOC_DAILINK_REG(ac97_aux),
+},
+};
+
+static struct snd_soc_card tosa = {
+	.name = "Tosa",
+	.owner = THIS_MODULE,
+	.dai_link = tosa_dai,
+	.num_links = ARRAY_SIZE(tosa_dai),
+
+	.controls = tosa_controls,
+	.num_controls = ARRAY_SIZE(tosa_controls),
+	.dapm_widgets = tosa_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(tosa_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+	.fully_routed = true,
+};
+
+static int tosa_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &tosa;
+	int ret;
+
+	ret = gpio_request_one(TOSA_GPIO_L_MUTE, GPIOF_OUT_INIT_LOW,
+			       "Headphone Jack");
+	if (ret)
+		return ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret) {
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+		gpio_free(TOSA_GPIO_L_MUTE);
+	}
+	return ret;
+}
+
+static int tosa_remove(struct platform_device *pdev)
+{
+	gpio_free(TOSA_GPIO_L_MUTE);
+	return 0;
+}
+
+static struct platform_driver tosa_driver = {
+	.driver		= {
+		.name	= "tosa-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= tosa_probe,
+	.remove		= tosa_remove,
+};
+
+module_platform_driver(tosa_driver);
+
+/* Module information */
+MODULE_AUTHOR("Richard Purdie");
+MODULE_DESCRIPTION("ALSA SoC Tosa");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:tosa-audio");
diff --git a/marvell/linux/sound/soc/pxa/ttc-dkb.c b/marvell/linux/sound/soc/pxa/ttc-dkb.c
new file mode 100644
index 0000000..d8f79e2
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/ttc-dkb.c
@@ -0,0 +1,141 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * linux/sound/soc/pxa/ttc_dkb.c
+ *
+ * Copyright (C) 2012 Marvell International Ltd.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+#include <asm/mach-types.h>
+#include <sound/pcm_params.h>
+#include "../codecs/88pm860x-codec.h"
+
+static struct snd_soc_jack hs_jack, mic_jack;
+
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+	{ .pin = "Headset Stereophone",	.mask = SND_JACK_HEADPHONE, },
+};
+
+static struct snd_soc_jack_pin mic_jack_pins[] = {
+	{ .pin = "Headset Mic 2",	.mask = SND_JACK_MICROPHONE, },
+};
+
+/* ttc machine dapm widgets */
+static const struct snd_soc_dapm_widget ttc_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headset Stereophone", NULL),
+	SND_SOC_DAPM_LINE("Lineout Out 1", NULL),
+	SND_SOC_DAPM_LINE("Lineout Out 2", NULL),
+	SND_SOC_DAPM_SPK("Ext Speaker", NULL),
+	SND_SOC_DAPM_MIC("Ext Mic 1", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic 2", NULL),
+	SND_SOC_DAPM_MIC("Ext Mic 3", NULL),
+};
+
+/* ttc machine audio map */
+static const struct snd_soc_dapm_route ttc_audio_map[] = {
+	{"Headset Stereophone", NULL, "HS1"},
+	{"Headset Stereophone", NULL, "HS2"},
+
+	{"Ext Speaker", NULL, "LSP"},
+	{"Ext Speaker", NULL, "LSN"},
+
+	{"Lineout Out 1", NULL, "LINEOUT1"},
+	{"Lineout Out 2", NULL, "LINEOUT2"},
+
+	{"MIC1P", NULL, "Mic1 Bias"},
+	{"MIC1N", NULL, "Mic1 Bias"},
+	{"Mic1 Bias", NULL, "Ext Mic 1"},
+
+	{"MIC2P", NULL, "Mic1 Bias"},
+	{"MIC2N", NULL, "Mic1 Bias"},
+	{"Mic1 Bias", NULL, "Headset Mic 2"},
+
+	{"MIC3P", NULL, "Mic3 Bias"},
+	{"MIC3N", NULL, "Mic3 Bias"},
+	{"Mic3 Bias", NULL, "Ext Mic 3"},
+};
+
+static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_component *component = rtd->codec_dai->component;
+
+	/* Headset jack detection */
+	snd_soc_card_jack_new(rtd->card, "Headphone Jack", SND_JACK_HEADPHONE |
+			      SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2,
+			      &hs_jack, hs_jack_pins, ARRAY_SIZE(hs_jack_pins));
+	snd_soc_card_jack_new(rtd->card, "Microphone Jack", SND_JACK_MICROPHONE,
+			      &mic_jack, mic_jack_pins,
+			      ARRAY_SIZE(mic_jack_pins));
+
+	/* headphone, microphone detection & headset short detection */
+	pm860x_hs_jack_detect(component, &hs_jack, SND_JACK_HEADPHONE,
+			      SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2);
+	pm860x_mic_jack_detect(component, &hs_jack, SND_JACK_MICROPHONE);
+
+	return 0;
+}
+
+/* ttc/td-dkb digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(i2s,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.1")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("88pm860x-codec", "88pm860x-i2s")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("mmp-pcm-audio")));
+
+static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = {
+{
+	 .name = "88pm860x i2s",
+	 .stream_name = "audio playback",
+	 .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBM_CFM,
+	 .init = ttc_pm860x_init,
+	 SND_SOC_DAILINK_REG(i2s),
+},
+};
+
+/* ttc/td audio machine driver */
+static struct snd_soc_card ttc_dkb_card = {
+	.name = "ttc-dkb-hifi",
+	.owner = THIS_MODULE,
+	.dai_link = ttc_pm860x_hifi_dai,
+	.num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai),
+
+	.dapm_widgets = ttc_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(ttc_dapm_widgets),
+	.dapm_routes = ttc_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(ttc_audio_map),
+};
+
+static int ttc_dkb_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &ttc_dkb_card;
+	int ret;
+
+	card->dev = &pdev->dev;
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+			ret);
+
+	return ret;
+}
+
+static struct platform_driver ttc_dkb_driver = {
+	.driver		= {
+		.name	= "ttc-dkb-audio",
+		.pm     = &snd_soc_pm_ops,
+	},
+	.probe		= ttc_dkb_probe,
+};
+
+module_platform_driver(ttc_dkb_driver);
+
+/* Module information */
+MODULE_AUTHOR("Qiao Zhou, <zhouqiao@marvell.com>");
+MODULE_DESCRIPTION("ALSA SoC TTC DKB");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ttc-dkb-audio");
diff --git a/marvell/linux/sound/soc/pxa/z2.c b/marvell/linux/sound/soc/pxa/z2.c
new file mode 100644
index 0000000..f9a33cb
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/z2.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/sound/soc/pxa/z2.c
+ *
+ * SoC Audio driver for Aeronix Zipit Z2
+ *
+ * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com>
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/audio.h>
+#include <mach/z2.h>
+
+#include "../codecs/wm8750.h"
+#include "pxa2xx-i2s.h"
+
+static struct snd_soc_card snd_soc_z2;
+
+static int z2_hw_params(struct snd_pcm_substream *substream,
+	struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int clk = 0;
+	int ret = 0;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		clk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		clk = 11289600;
+		break;
+	}
+
+	/* set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	/* set the I2S system clock as input (unused) */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+		SND_SOC_CLOCK_IN);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static struct snd_soc_jack hs_jack;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+	{
+		.pin	= "Mic Jack",
+		.mask	= SND_JACK_MICROPHONE,
+	},
+	{
+		.pin	= "Headphone Jack",
+		.mask	= SND_JACK_HEADPHONE,
+	},
+	{
+		.pin    = "Ext Spk",
+		.mask   = SND_JACK_HEADPHONE,
+		.invert = 1
+	},
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+	{
+		.gpio		= GPIO37_ZIPITZ2_HEADSET_DETECT,
+		.name		= "hsdet-gpio",
+		.report		= SND_JACK_HEADSET,
+		.debounce_time	= 200,
+		.invert		= 1,
+	},
+};
+
+/* z2 machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_SPK("Ext Spk", NULL),
+
+	/* headset is a mic and mono headphone */
+	SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Z2 machine audio_map */
+static const struct snd_soc_dapm_route z2_audio_map[] = {
+
+	/* headphone connected to LOUT1, ROUT1 */
+	{"Headphone Jack", NULL, "LOUT1"},
+	{"Headphone Jack", NULL, "ROUT1"},
+
+	/* ext speaker connected to LOUT2, ROUT2  */
+	{"Ext Spk", NULL, "ROUT2"},
+	{"Ext Spk", NULL, "LOUT2"},
+
+	/* mic is connected to R input 2 - with bias */
+	{"RINPUT2", NULL, "Mic Bias"},
+	{"Mic Bias", NULL, "Mic Jack"},
+};
+
+/*
+ * Logic for a wm8750 as connected on a Z2 Device
+ */
+static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd)
+{
+	int ret;
+
+	/* Jack detection API stuff */
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", SND_JACK_HEADSET,
+				    &hs_jack, hs_jack_pins,
+				    ARRAY_SIZE(hs_jack_pins));
+	if (ret)
+		goto err;
+
+	ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+				hs_jack_gpios);
+	if (ret)
+		goto err;
+
+	return 0;
+
+err:
+	return ret;
+}
+
+static const struct snd_soc_ops z2_ops = {
+	.hw_params = z2_hw_params,
+};
+
+/* z2 digital audio interface glue - connects codec <--> CPU */
+SND_SOC_DAILINK_DEFS(wm8750,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-i2s")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm8750.0-001b", "wm8750-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link z2_dai = {
+	.name		= "wm8750",
+	.stream_name	= "WM8750",
+	.init		= z2_wm8750_init,
+	.dai_fmt	= SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			  SND_SOC_DAIFMT_CBS_CFS,
+	.ops		= &z2_ops,
+	SND_SOC_DAILINK_REG(wm8750),
+};
+
+/* z2 audio machine driver */
+static struct snd_soc_card snd_soc_z2 = {
+	.name		= "Z2",
+	.owner		= THIS_MODULE,
+	.dai_link	= &z2_dai,
+	.num_links	= 1,
+
+	.dapm_widgets = wm8750_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(wm8750_dapm_widgets),
+	.dapm_routes = z2_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(z2_audio_map),
+	.fully_routed = true,
+};
+
+static struct platform_device *z2_snd_device;
+
+static int __init z2_init(void)
+{
+	int ret;
+
+	if (!machine_is_zipit2())
+		return -ENODEV;
+
+	z2_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!z2_snd_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(z2_snd_device, &snd_soc_z2);
+	ret = platform_device_add(z2_snd_device);
+
+	if (ret)
+		platform_device_put(z2_snd_device);
+
+	return ret;
+}
+
+static void __exit z2_exit(void)
+{
+	platform_device_unregister(z2_snd_device);
+}
+
+module_init(z2_init);
+module_exit(z2_exit);
+
+MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, "
+		"Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC ZipitZ2");
+MODULE_LICENSE("GPL");
diff --git a/marvell/linux/sound/soc/pxa/zylonite.c b/marvell/linux/sound/soc/pxa/zylonite.c
new file mode 100644
index 0000000..567dc13
--- /dev/null
+++ b/marvell/linux/sound/soc/pxa/zylonite.c
@@ -0,0 +1,266 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * zylonite.c  --  SoC audio for Zylonite
+ *
+ * Copyright 2008 Wolfson Microelectronics PLC.
+ * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include "../codecs/wm9713.h"
+#include "pxa-ssp.h"
+
+/*
+ * There is a physical switch SW15 on the board which changes the MCLK
+ * for the WM9713 between the standard AC97 master clock and the
+ * output of the CLK_POUT signal from the PXA.
+ */
+static int clk_pout;
+module_param(clk_pout, int, 0);
+MODULE_PARM_DESC(clk_pout, "Use CLK_POUT as WM9713 MCLK (SW15 on board).");
+
+static struct clk *pout;
+
+static struct snd_soc_card zylonite;
+
+static const struct snd_soc_dapm_widget zylonite_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone", NULL),
+	SND_SOC_DAPM_MIC("Headset Microphone", NULL),
+	SND_SOC_DAPM_MIC("Handset Microphone", NULL),
+	SND_SOC_DAPM_SPK("Multiactor", NULL),
+	SND_SOC_DAPM_SPK("Headset Earpiece", NULL),
+};
+
+/* Currently supported audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+	/* Headphone output connected to HPL/HPR */
+	{ "Headphone", NULL,  "HPL" },
+	{ "Headphone", NULL,  "HPR" },
+
+	/* On-board earpiece */
+	{ "Headset Earpiece", NULL, "OUT3" },
+
+	/* Headphone mic */
+	{ "MIC2A", NULL, "Mic Bias" },
+	{ "Mic Bias", NULL, "Headset Microphone" },
+
+	/* On-board mic */
+	{ "MIC1", NULL, "Mic Bias" },
+	{ "Mic Bias", NULL, "Handset Microphone" },
+
+	/* Multiactor differentially connected over SPKL/SPKR */
+	{ "Multiactor", NULL, "SPKL" },
+	{ "Multiactor", NULL, "SPKR" },
+};
+
+static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd)
+{
+	if (clk_pout)
+		snd_soc_dai_set_pll(rtd->codec_dai, 0, 0,
+				    clk_get_rate(pout), 0);
+
+	return 0;
+}
+
+static int zylonite_voice_hw_params(struct snd_pcm_substream *substream,
+				    struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int wm9713_div = 0;
+	int ret = 0;
+	int rate = params_rate(params);
+
+	/* Only support ratios that we can generate neatly from the AC97
+	 * based master clock - in particular, this excludes 44.1kHz.
+	 * In most applications the voice DAC will be used for telephony
+	 * data so multiples of 8kHz will be the common case.
+	 */
+	switch (rate) {
+	case 8000:
+		wm9713_div = 12;
+		break;
+	case 16000:
+		wm9713_div = 6;
+		break;
+	case 48000:
+		wm9713_div = 2;
+		break;
+	default:
+		/* Don't support OSS emulation */
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, PXA_SSP_CLK_AUDIO, 0, 1);
+	if (ret < 0)
+		return ret;
+
+	if (clk_pout)
+		ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_PLL_DIV,
+					     WM9713_PCMDIV(wm9713_div));
+	else
+		ret = snd_soc_dai_set_clkdiv(codec_dai, WM9713_PCMCLK_DIV,
+					     WM9713_PCMDIV(wm9713_div));
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static const struct snd_soc_ops zylonite_voice_ops = {
+	.hw_params = zylonite_voice_hw_params,
+};
+
+SND_SOC_DAILINK_DEFS(ac97,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-hifi")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(ac97_aux,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa2xx-ac97-aux")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-aux")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+SND_SOC_DAILINK_DEFS(voice,
+	DAILINK_COMP_ARRAY(COMP_CPU("pxa-ssp-dai.2")),
+	DAILINK_COMP_ARRAY(COMP_CODEC("wm9713-codec", "wm9713-voice")),
+	DAILINK_COMP_ARRAY(COMP_PLATFORM("pxa-pcm-audio")));
+
+static struct snd_soc_dai_link zylonite_dai[] = {
+{
+	.name = "AC97",
+	.stream_name = "AC97 HiFi",
+	.init = zylonite_wm9713_init,
+	SND_SOC_DAILINK_REG(ac97),
+},
+{
+	.name = "AC97 Aux",
+	.stream_name = "AC97 Aux",
+	SND_SOC_DAILINK_REG(ac97_aux),
+},
+{
+	.name = "WM9713 Voice",
+	.stream_name = "WM9713 Voice",
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+	.ops = &zylonite_voice_ops,
+	SND_SOC_DAILINK_REG(voice),
+},
+};
+
+static int zylonite_probe(struct snd_soc_card *card)
+{
+	int ret;
+
+	if (clk_pout) {
+		pout = clk_get(NULL, "CLK_POUT");
+		if (IS_ERR(pout)) {
+			dev_err(card->dev, "Unable to obtain CLK_POUT: %ld\n",
+				PTR_ERR(pout));
+			return PTR_ERR(pout);
+		}
+
+		ret = clk_enable(pout);
+		if (ret != 0) {
+			dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
+				ret);
+			clk_put(pout);
+			return ret;
+		}
+
+		dev_dbg(card->dev, "MCLK enabled at %luHz\n",
+			clk_get_rate(pout));
+	}
+
+	return 0;
+}
+
+static int zylonite_remove(struct snd_soc_card *card)
+{
+	if (clk_pout) {
+		clk_disable(pout);
+		clk_put(pout);
+	}
+
+	return 0;
+}
+
+static int zylonite_suspend_post(struct snd_soc_card *card)
+{
+	if (clk_pout)
+		clk_disable(pout);
+
+	return 0;
+}
+
+static int zylonite_resume_pre(struct snd_soc_card *card)
+{
+	int ret = 0;
+
+	if (clk_pout) {
+		ret = clk_enable(pout);
+		if (ret != 0)
+			dev_err(card->dev, "Unable to enable CLK_POUT: %d\n",
+				ret);
+	}
+
+	return ret;
+}
+
+static struct snd_soc_card zylonite = {
+	.name = "Zylonite",
+	.owner = THIS_MODULE,
+	.probe = &zylonite_probe,
+	.remove = &zylonite_remove,
+	.suspend_post = &zylonite_suspend_post,
+	.resume_pre = &zylonite_resume_pre,
+	.dai_link = zylonite_dai,
+	.num_links = ARRAY_SIZE(zylonite_dai),
+
+	.dapm_widgets = zylonite_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(zylonite_dapm_widgets),
+	.dapm_routes = audio_map,
+	.num_dapm_routes = ARRAY_SIZE(audio_map),
+};
+
+static struct platform_device *zylonite_snd_ac97_device;
+
+static int __init zylonite_init(void)
+{
+	int ret;
+
+	zylonite_snd_ac97_device = platform_device_alloc("soc-audio", -1);
+	if (!zylonite_snd_ac97_device)
+		return -ENOMEM;
+
+	platform_set_drvdata(zylonite_snd_ac97_device, &zylonite);
+
+	ret = platform_device_add(zylonite_snd_ac97_device);
+	if (ret != 0)
+		platform_device_put(zylonite_snd_ac97_device);
+
+	return ret;
+}
+
+static void __exit zylonite_exit(void)
+{
+	platform_device_unregister(zylonite_snd_ac97_device);
+}
+
+module_init(zylonite_init);
+module_exit(zylonite_exit);
+
+MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
+MODULE_DESCRIPTION("ALSA SoC WM9713 Zylonite");
+MODULE_LICENSE("GPL");