Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1424755 > unrolled thread

[alsa-devel] [PATCH v5 0/9] ASoC: Mediatek: Add support for MT2701 SOC

Started byGarlic Tseng <garlic.tseng@mediatek.com>
First post2016-06-17 09:50 +0200
Last post2016-06-17 09:50 +0200
Articles 6 — 1 participant

Back to article view | Back to linux.kernel


Contents

  [alsa-devel] [PATCH v5 0/9] ASoC: Mediatek: Add support for MT2701 SOC Garlic Tseng <garlic.tseng@mediatek.com> - 2016-06-17 09:50 +0200
    [alsa-devel] [PATCH v5 2/9] ASoC: mediatek: implement mediatek common structure Garlic Tseng <garlic.tseng@mediatek.com> - 2016-06-17 09:50 +0200
    [alsa-devel] [PATCH v5 5/9] ASoC: mediatek: add structure define and clock control for 2701 Garlic Tseng <garlic.tseng@mediatek.com> - 2016-06-17 09:50 +0200
    [alsa-devel] [PATCH v5 8/9] ASoC: mediatek: add BT implementation Garlic Tseng <garlic.tseng@mediatek.com> - 2016-06-17 09:50 +0200
    [alsa-devel] [PATCH v5 3/9] ASoC: mediatek: let mt8173 use mediatek common structure Garlic Tseng <garlic.tseng@mediatek.com> - 2016-06-17 09:50 +0200
    [alsa-devel] [PATCH v5 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option. Garlic Tseng <garlic.tseng@mediatek.com> - 2016-06-17 09:50 +0200

#1424755 — [alsa-devel] [PATCH v5 0/9] ASoC: Mediatek: Add support for MT2701 SOC

FromGarlic Tseng <garlic.tseng@mediatek.com>
Date2016-06-17 09:50 +0200
Subject[alsa-devel] [PATCH v5 0/9] ASoC: Mediatek: Add support for MT2701 SOC
Message-ID<rKWHo-3Cb-11@gated-at.bofh.it>
This patch adds basic support for Mediatek AFE for MT2701 SoC.
The patch is based on broonie tree "for-next" branch.

Change since v4:

* remove SND_SOC_MEDIATEK config prompt
* fix config prompt to meaningful one for SND_SOC_MT2701_CS42448
* remove some unnecessary random space change

Change since v3:

* fix comments style.

Change since v2:

* fix comments style.
* replace EXPORT_SYMBOL with EXPORT_SYMBOL_GPL
* reduce debug message
* move mutex lock for irq-allocated to AFE struct
* remove func mtk_simple_isr and call snd_pcm_period_elapsed directly
* mt2701 driver probe will fail if clock initial error
* fix dapm on/off switch control naming

Change since v1:

implement common private structure, fe dai and platform driver.
let mt8173 and mt2701 use the common structure.


Garlic Tseng (9):
  ASoC: mediatek: Refine mt8173 driver and change config option
  ASoC: mediatek: implement mediatek common structure
  ASoC: mediatek: let mt8173 use mediatek common structure
  ASoC: mediatek: add documents for mt2701
  ASoC: mediatek: add structure define and clock control for 2701
  ASoC: mediatek: add mt2701 platform driver implementation.
  ASoC: bt-sco: extend rate and add a general compatible string
  ASoC: mediatek: add BT implementation
  ASoC: mediatek: Add mt2701-cs42448 driver and config option.

 Documentation/devicetree/bindings/sound/bt-sco.txt |    2 +-
 .../devicetree/bindings/sound/mt2701-afe-pcm.txt   |  150 ++
 .../devicetree/bindings/sound/mt2701-cs42448.txt   |   43 +
 sound/soc/codecs/bt-sco.c                          |    5 +-
 sound/soc/mediatek/Kconfig                         |   37 +-
 sound/soc/mediatek/Makefile                        |   10 +-
 sound/soc/mediatek/common/Makefile                 |   16 +
 sound/soc/mediatek/common/mtk-afe-fe-dai.c         |  379 +++++
 sound/soc/mediatek/common/mtk-afe-fe-dai.h         |   45 +
 .../soc/mediatek/common/mtk-afe-platform-driver.c  |   90 ++
 .../soc/mediatek/common/mtk-afe-platform-driver.h  |   23 +
 sound/soc/mediatek/common/mtk-base-afe.h           |  104 ++
 sound/soc/mediatek/mt2701/Makefile                 |   19 +
 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c  |  464 ++++++
 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h  |   38 +
 sound/soc/mediatek/mt2701/mt2701-afe-common.h      |  181 +++
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c         | 1698 ++++++++++++++++++++
 sound/soc/mediatek/mt2701/mt2701-cs42448.c         |  422 +++++
 sound/soc/mediatek/mt2701/mt2701-reg.h             |  186 +++
 sound/soc/mediatek/mt8173/Makefile                 |    7 +
 sound/soc/mediatek/mt8173/mt8173-afe-common.h      |   73 +
 .../{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c}     |  921 +++++------
 sound/soc/mediatek/{ => mt8173}/mt8173-max98090.c  |    2 +-
 .../mediatek/{ => mt8173}/mt8173-rt5650-rt5514.c   |    2 +-
 .../mediatek/{ => mt8173}/mt8173-rt5650-rt5676.c   |    4 +-
 sound/soc/mediatek/{ => mt8173}/mt8173-rt5650.c    |    2 +-
 sound/soc/mediatek/mtk-afe-common.h                |  101 --
 27 files changed, 4390 insertions(+), 634 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt
 create mode 100644 Documentation/devicetree/bindings/sound/mt2701-cs42448.txt
 create mode 100644 sound/soc/mediatek/common/Makefile
 create mode 100644 sound/soc/mediatek/common/mtk-afe-fe-dai.c
 create mode 100644 sound/soc/mediatek/common/mtk-afe-fe-dai.h
 create mode 100644 sound/soc/mediatek/common/mtk-afe-platform-driver.c
 create mode 100644 sound/soc/mediatek/common/mtk-afe-platform-driver.h
 create mode 100644 sound/soc/mediatek/common/mtk-base-afe.h
 create mode 100644 sound/soc/mediatek/mt2701/Makefile
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-common.h
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-reg.h
 create mode 100644 sound/soc/mediatek/mt8173/Makefile
 create mode 100644 sound/soc/mediatek/mt8173/mt8173-afe-common.h
 rename sound/soc/mediatek/{mtk-afe-pcm.c => mt8173/mt8173-afe-pcm.c} (51%)
 rename sound/soc/mediatek/{ => mt8173}/mt8173-max98090.c (99%)
 rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650-rt5514.c (99%)
 rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650-rt5676.c (99%)
 rename sound/soc/mediatek/{ => mt8173}/mt8173-rt5650.c (99%)
 delete mode 100644 sound/soc/mediatek/mtk-afe-common.h

-- 
1.9.1

[toc] | [next] | [standalone]


#1424757 — [alsa-devel] [PATCH v5 2/9] ASoC: mediatek: implement mediatek common structure

FromGarlic Tseng <garlic.tseng@mediatek.com>
Date2016-06-17 09:50 +0200
Subject[alsa-devel] [PATCH v5 2/9] ASoC: mediatek: implement mediatek common structure
Message-ID<rKWHo-3Cb-23@gated-at.bofh.it>
In reply to#1424755
implement mediatek basic structure, include common private data,
afe fe dai operator and afe platform driver.

Signed-off-by: Garlic Tseng <garlic.tseng@mediatek.com>
---
 sound/soc/mediatek/common/mtk-afe-fe-dai.c         | 379 +++++++++++++++++++++
 sound/soc/mediatek/common/mtk-afe-fe-dai.h         |  45 +++
 .../soc/mediatek/common/mtk-afe-platform-driver.c  |  90 +++++
 .../soc/mediatek/common/mtk-afe-platform-driver.h  |  23 ++
 sound/soc/mediatek/common/mtk-base-afe.h           | 104 ++++++
 5 files changed, 641 insertions(+)
 create mode 100644 sound/soc/mediatek/common/mtk-afe-fe-dai.c
 create mode 100644 sound/soc/mediatek/common/mtk-afe-fe-dai.h
 create mode 100644 sound/soc/mediatek/common/mtk-afe-platform-driver.c
 create mode 100644 sound/soc/mediatek/common/mtk-afe-platform-driver.h
 create mode 100644 sound/soc/mediatek/common/mtk-base-afe.h

diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
new file mode 100644
index 0000000..b788791b
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c
@@ -0,0 +1,379 @@
+/*
+ * mtk-afe-fe-dais.c  --  Mediatek afe fe dai operator
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "mtk-afe-fe-dai.h"
+#include "mtk-base-afe.h"
+
+#define AFE_BASE_END_OFFSET 8
+
+int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask,
+			   unsigned int val)
+{
+	if (reg < 0)
+		return 0;
+	return regmap_update_bits(map, reg, mask, val);
+}
+
+int mtk_regmap_write(struct regmap *map, int reg, unsigned int val)
+{
+	if (reg < 0)
+		return 0;
+	return regmap_write(map, reg, val);
+}
+
+int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	int memif_num = rtd->cpu_dai->id;
+	struct mtk_base_afe_memif *memif = &afe->memif[memif_num];
+	const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware;
+	int ret;
+
+	memif->substream = substream;
+
+	snd_pcm_hw_constraint_step(substream->runtime, 0,
+				   SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16);
+	/* enable agent */
+	mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
+			       1 << memif->data->agent_disable_shift,
+			       0 << memif->data->agent_disable_shift);
+
+	snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware);
+
+	/*
+	 * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be
+	 * smaller than period_size due to AFE's internal buffer.
+	 * This easily leads to overrun when avail_min is period_size.
+	 * One more period can hold the possible unread buffer.
+	 */
+	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+		int periods_max = mtk_afe_hardware->periods_max;
+
+		ret = snd_pcm_hw_constraint_minmax(runtime,
+						   SNDRV_PCM_HW_PARAM_PERIODS,
+						   3, periods_max);
+		if (ret < 0) {
+			dev_err(afe->dev, "hw_constraint_minmax failed\n");
+			return ret;
+		}
+	}
+
+	ret = snd_pcm_hw_constraint_integer(runtime,
+					    SNDRV_PCM_HW_PARAM_PERIODS);
+	if (ret < 0)
+		dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
+
+	/* dynamic allocate irq to memif */
+	if (memif->irq_usage < 0) {
+		int irq_id = mtk_dynamic_irq_acquire(afe);
+
+		if (irq_id != afe->irqs_size) {
+			/* link */
+			memif->irq_usage = irq_id;
+		} else {
+			dev_err(afe->dev, "%s() error: no more asys irq\n",
+				__func__);
+			ret = -EBUSY;
+		}
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_startup);
+
+void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	int irq_id;
+
+	irq_id = memif->irq_usage;
+
+	mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg,
+			       1 << memif->data->agent_disable_shift,
+			       1 << memif->data->agent_disable_shift);
+
+	if (!memif->const_irq) {
+		mtk_dynamic_irq_release(afe, irq_id);
+		memif->irq_usage = -1;
+		memif->substream = NULL;
+	}
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown);
+
+int mtk_afe_fe_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 mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	int msb_at_bit33 = 0;
+	int ret, fs = 0;
+
+	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
+	if (ret < 0)
+		return ret;
+
+	msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0;
+	memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
+	memif->buffer_size = substream->runtime->dma_bytes;
+
+	/* start */
+	mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base,
+			 memif->phys_buf_addr);
+	/* end */
+	mtk_regmap_write(afe->regmap,
+			 memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
+			 memif->phys_buf_addr + memif->buffer_size - 1);
+
+	/* set MSB to 33-bit */
+	mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg,
+			       1 << memif->data->msb_shift,
+			       msb_at_bit33 << memif->data->msb_shift);
+
+	/* set channel */
+	if (memif->data->mono_shift >= 0) {
+		unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
+
+		mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg,
+				       1 << memif->data->mono_shift,
+				       mono << memif->data->mono_shift);
+	}
+
+	/* set rate */
+	if (memif->data->fs_shift < 0)
+		return 0;
+
+	fs = afe->memif_fs(substream, params_rate(params));
+
+	if (fs < 0)
+		return -EINVAL;
+
+	mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg,
+			       memif->data->fs_maskbit << memif->data->fs_shift,
+			       fs << memif->data->fs_shift);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params);
+
+int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai)
+{
+	return snd_pcm_lib_free_pages(substream);
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free);
+
+int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+		       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_pcm_runtime * const runtime = substream->runtime;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage];
+	const struct mtk_base_irq_data *irq_data = irqs->irq_data;
+	unsigned int counter = runtime->period_size;
+	int fs;
+
+	dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+		if (memif->data->enable_shift >= 0)
+			mtk_regmap_update_bits(afe->regmap,
+					       memif->data->enable_reg,
+					       1 << memif->data->enable_shift,
+					       1 << memif->data->enable_shift);
+
+		/* set irq counter */
+		mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg,
+				       irq_data->irq_cnt_maskbit
+				       << irq_data->irq_cnt_shift,
+				       counter << irq_data->irq_cnt_shift);
+
+		/* set irq fs */
+		fs = afe->irq_fs(substream, runtime->rate);
+
+		if (fs < 0)
+			return -EINVAL;
+
+		mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg,
+				       irq_data->irq_fs_maskbit
+				       << irq_data->irq_fs_shift,
+				       fs << irq_data->irq_fs_shift);
+
+		/* enable interrupt */
+		mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
+				       1 << irq_data->irq_en_shift,
+				       1 << irq_data->irq_en_shift);
+
+		return 0;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg,
+				       1 << memif->data->enable_shift, 0);
+		/* disable interrupt */
+		mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg,
+				       1 << irq_data->irq_en_shift,
+				       0 << irq_data->irq_en_shift);
+		/* and clear pending IRQ */
+		mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg,
+				 1 << irq_data->irq_clr_shift);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger);
+
+int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd  = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	int hd_audio = 0;
+
+	/* set hd mode */
+	switch (substream->runtime->format) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		hd_audio = 0;
+		break;
+	case SNDRV_PCM_FORMAT_S32_LE:
+		hd_audio = 1;
+		break;
+	case SNDRV_PCM_FORMAT_S24_LE:
+		hd_audio = 1;
+		break;
+	default:
+		dev_err(afe->dev, "%s() error: unsupported format %d\n",
+			__func__, substream->runtime->format);
+		break;
+	}
+
+	mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg,
+			       1 << memif->data->hd_shift,
+			       hd_audio << memif->data->hd_shift);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare);
+
+const struct snd_soc_dai_ops mtk_afe_fe_ops = {
+	.startup	= mtk_afe_fe_startup,
+	.shutdown	= mtk_afe_fe_shutdown,
+	.hw_params	= mtk_afe_fe_hw_params,
+	.hw_free	= mtk_afe_fe_hw_free,
+	.prepare	= mtk_afe_fe_prepare,
+	.trigger	= mtk_afe_fe_trigger,
+};
+EXPORT_SYMBOL_GPL(mtk_afe_fe_ops);
+
+static DEFINE_MUTEX(irqs_lock);
+int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe)
+{
+	int i;
+
+	mutex_lock(&afe->irq_alloc_lock);
+	for (i = 0; i < afe->irqs_size; ++i) {
+		if (afe->irqs[i].irq_occupyed == 0) {
+			afe->irqs[i].irq_occupyed = 1;
+			mutex_unlock(&afe->irq_alloc_lock);
+			return i;
+		}
+	}
+	mutex_unlock(&afe->irq_alloc_lock);
+	return afe->irqs_size;
+}
+EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire);
+
+int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id)
+{
+	mutex_lock(&afe->irq_alloc_lock);
+	if (irq_id >= 0 && irq_id < afe->irqs_size) {
+		afe->irqs[irq_id].irq_occupyed = 0;
+		mutex_unlock(&afe->irq_alloc_lock);
+		return 0;
+	}
+	mutex_unlock(&afe->irq_alloc_lock);
+	return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release);
+
+int mtk_afe_dai_suspend(struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct device *dev = afe->dev;
+	struct regmap *regmap = afe->regmap;
+	int i;
+
+	if (pm_runtime_status_suspended(dev) || afe->suspended)
+		return 0;
+
+	if (!afe->reg_back_up)
+		afe->reg_back_up =
+			devm_kcalloc(dev, afe->reg_back_up_list_num,
+				     sizeof(unsigned int), GFP_KERNEL);
+
+	for (i = 0; i < afe->reg_back_up_list_num; i++)
+		regmap_read(regmap, afe->reg_back_up_list[i],
+			    &afe->reg_back_up[i]);
+
+	afe->suspended = true;
+	afe->runtime_suspend(dev);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend);
+
+int mtk_afe_dai_resume(struct snd_soc_dai *dai)
+{
+	struct mtk_base_afe *afe = dev_get_drvdata(dai->dev);
+	struct device *dev = afe->dev;
+	struct regmap *regmap = afe->regmap;
+	int i = 0;
+
+	if (pm_runtime_status_suspended(dev) || !afe->suspended)
+		return 0;
+
+	afe->runtime_resume(dev);
+
+	if (!afe->reg_back_up)
+		dev_dbg(dev, "%s no reg_backup\n", __func__);
+
+	for (i = 0; i < afe->reg_back_up_list_num; i++)
+		mtk_regmap_write(regmap, afe->reg_back_up_list[i],
+				 afe->reg_back_up[i]);
+
+	afe->suspended = false;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_afe_dai_resume);
+
+MODULE_DESCRIPTION("Mediatek simple fe dai operator");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
new file mode 100644
index 0000000..28cb178
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h
@@ -0,0 +1,45 @@
+/*
+ * mtk-afe-fe-dais.h  --  Mediatek afe fe dai operator definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _MTK_AFE_FE_DAI_H_
+#define _MTK_AFE_FE_DAI_H_
+
+struct snd_soc_dai_ops;
+struct mtk_base_afe;
+struct mtk_base_afe_memif;
+
+int mtk_afe_fe_startup(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai);
+void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream,
+			 struct snd_soc_dai *dai);
+int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params,
+			 struct snd_soc_dai *dai);
+int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai);
+int mtk_afe_fe_prepare(struct snd_pcm_substream *substream,
+		       struct snd_soc_dai *dai);
+int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd,
+		       struct snd_soc_dai *dai);
+
+extern const struct snd_soc_dai_ops mtk_afe_fe_ops;
+
+int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe);
+int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id);
+int mtk_afe_dai_suspend(struct snd_soc_dai *dai);
+int mtk_afe_dai_resume(struct snd_soc_dai *dai);
+
+#endif
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
new file mode 100644
index 0000000..82d439c
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c
@@ -0,0 +1,90 @@
+/*
+ * mtk-afe-platform-driver.c  --  Mediatek afe platform driver
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/dma-mapping.h>
+#include <sound/soc.h>
+
+#include "mtk-afe-platform-driver.h"
+#include "mtk-base-afe.h"
+
+static snd_pcm_uframes_t mtk_afe_pcm_pointer
+			 (struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	const struct mtk_base_memif_data *memif_data = memif->data;
+	struct regmap *regmap = afe->regmap;
+	struct device *dev = afe->dev;
+	int reg_ofs_base = memif_data->reg_ofs_base;
+	int reg_ofs_cur = memif_data->reg_ofs_cur;
+	unsigned int hw_ptr = 0, hw_base = 0;
+	int ret, pcm_ptr_bytes;
+
+	ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr);
+	if (ret || hw_ptr == 0) {
+		dev_err(dev, "%s hw_ptr err\n", __func__);
+		pcm_ptr_bytes = 0;
+		goto POINTER_RETURN_FRAMES;
+	}
+
+	ret = regmap_read(regmap, reg_ofs_base, &hw_base);
+	if (ret || hw_base == 0) {
+		dev_err(dev, "%s hw_ptr err\n", __func__);
+		pcm_ptr_bytes = 0;
+		goto POINTER_RETURN_FRAMES;
+	}
+
+	pcm_ptr_bytes = hw_ptr - hw_base;
+
+POINTER_RETURN_FRAMES:
+	return bytes_to_frames(substream->runtime, pcm_ptr_bytes);
+}
+
+static const struct snd_pcm_ops mtk_afe_pcm_ops = {
+	.ioctl = snd_pcm_lib_ioctl,
+	.pointer = mtk_afe_pcm_pointer,
+};
+
+static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
+{
+	size_t size;
+	struct snd_card *card = rtd->card->snd_card;
+	struct snd_pcm *pcm = rtd->pcm;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+
+	size = afe->mtk_afe_hardware->buffer_bytes_max;
+	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+						     card->dev, size, size);
+}
+
+static void mtk_afe_pcm_free(struct snd_pcm *pcm)
+{
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+const struct snd_soc_platform_driver mtk_afe_pcm_platform = {
+	.ops = &mtk_afe_pcm_ops,
+	.pcm_new = mtk_afe_pcm_new,
+	.pcm_free = mtk_afe_pcm_free,
+};
+EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform);
+
+MODULE_DESCRIPTION("Mediatek simple platform driver");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
new file mode 100644
index 0000000..a973fc9
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h
@@ -0,0 +1,23 @@
+/*
+ * mtk-afe-platform-driver.h  --  Mediatek afe platform driver definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _MTK_AFE_PLATFORM_DRIVER_H_
+#define _MTK_AFE_PLATFORM_DRIVER_H_
+
+extern const struct snd_soc_platform_driver mtk_afe_pcm_platform;
+
+#endif
+
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h
new file mode 100644
index 0000000..3a78f6f
--- /dev/null
+++ b/sound/soc/mediatek/common/mtk-base-afe.h
@@ -0,0 +1,104 @@
+/*
+ * mtk-base-afe.h  --  Mediatek base afe structure
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _MTK_BASE_AFE_H_
+#define _MTK_BASE_AFE_H_
+
+struct mtk_base_memif_data {
+	int id;
+	const char *name;
+	int reg_ofs_base;
+	int reg_ofs_cur;
+	int fs_reg;
+	int fs_shift;
+	int fs_maskbit;
+	int mono_reg;
+	int mono_shift;
+	int enable_reg;
+	int enable_shift;
+	int hd_reg;
+	int hd_shift;
+	int msb_reg;
+	int msb_shift;
+	int agent_disable_reg;
+	int agent_disable_shift;
+};
+
+struct mtk_base_irq_data {
+	int id;
+	int irq_cnt_reg;
+	int irq_cnt_shift;
+	int irq_cnt_maskbit;
+	int irq_fs_reg;
+	int irq_fs_shift;
+	int irq_fs_maskbit;
+	int irq_en_reg;
+	int irq_en_shift;
+	int irq_clr_reg;
+	int irq_clr_shift;
+};
+
+struct device;
+struct mtk_base_afe_memif;
+struct mtk_base_afe_irq;
+struct regmap;
+struct snd_pcm_substream;
+struct snd_soc_dai;
+
+struct mtk_base_afe {
+	void __iomem *base_addr;
+	struct device *dev;
+	struct regmap *regmap;
+	struct mutex irq_alloc_lock; /* dynamic alloc irq lock */
+
+	unsigned int const *reg_back_up_list;
+	unsigned int *reg_back_up;
+	unsigned int reg_back_up_list_num;
+
+	int (*runtime_suspend)(struct device *dev);
+	int (*runtime_resume)(struct device *dev);
+	bool suspended;
+
+	struct mtk_base_afe_memif *memif;
+	int memif_size;
+	struct mtk_base_afe_irq *irqs;
+	int irqs_size;
+
+	const struct snd_pcm_hardware *mtk_afe_hardware;
+	int (*memif_fs)(struct snd_pcm_substream *substream,
+			unsigned int rate);
+	int (*irq_fs)(struct snd_pcm_substream *substream,
+		      unsigned int rate);
+
+	void *platform_priv;
+};
+
+struct mtk_base_afe_memif {
+	unsigned int phys_buf_addr;
+	int buffer_size;
+	struct snd_pcm_substream *substream;
+	const struct mtk_base_memif_data *data;
+	int irq_usage;
+	int const_irq;
+};
+
+struct mtk_base_afe_irq {
+	const struct mtk_base_irq_data *irq_data;
+	int irq_occupyed;
+};
+
+#endif
+
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1424758 — [alsa-devel] [PATCH v5 5/9] ASoC: mediatek: add structure define and clock control for 2701

FromGarlic Tseng <garlic.tseng@mediatek.com>
Date2016-06-17 09:50 +0200
Subject[alsa-devel] [PATCH v5 5/9] ASoC: mediatek: add structure define and clock control for 2701
Message-ID<rKWHo-3Cb-29@gated-at.bofh.it>
In reply to#1424755
add structure define and clock control function for 2701.

Signed-off-by: Garlic Tseng <garlic.tseng@mediatek.com>
---
 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | 464 ++++++++++++++++++++++
 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h |  38 ++
 sound/soc/mediatek/mt2701/mt2701-afe-common.h     | 181 +++++++++
 sound/soc/mediatek/mt2701/mt2701-reg.h            | 186 +++++++++
 4 files changed, 869 insertions(+)
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-afe-common.h
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-reg.h

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
new file mode 100644
index 0000000..b815ecc
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c
@@ -0,0 +1,464 @@
+/*
+ * mt2701-afe-clock-ctrl.c  --  Mediatek 2701 afe clock ctrl
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <sound/soc.h>
+#include <linux/regmap.h>
+#include <linux/pm_runtime.h>
+
+#include "mt2701-afe-common.h"
+#include "mt2701-afe-clock-ctrl.h"
+
+static const char *aud_clks[MT2701_CLOCK_NUM] = {
+	[MT2701_AUD_INFRA_SYS_AUDIO] = "infra_sys_audio_clk",
+	[MT2701_AUD_AUD_MUX1_SEL] = "top_audio_mux1_sel",
+	[MT2701_AUD_AUD_MUX2_SEL] = "top_audio_mux2_sel",
+	[MT2701_AUD_AUD_MUX1_DIV] = "top_audio_mux1_div",
+	[MT2701_AUD_AUD_MUX2_DIV] = "top_audio_mux2_div",
+	[MT2701_AUD_AUD_48K_TIMING] = "top_audio_48k_timing",
+	[MT2701_AUD_AUD_44K_TIMING] = "top_audio_44k_timing",
+	[MT2701_AUD_AUDPLL_MUX_SEL] = "top_audpll_mux_sel",
+	[MT2701_AUD_APLL_SEL] = "top_apll_sel",
+	[MT2701_AUD_AUD1PLL_98M] = "top_aud1_pll_98M",
+	[MT2701_AUD_AUD2PLL_90M] = "top_aud2_pll_90M",
+	[MT2701_AUD_HADDS2PLL_98M] = "top_hadds2_pll_98M",
+	[MT2701_AUD_HADDS2PLL_294M] = "top_hadds2_pll_294M",
+	[MT2701_AUD_AUDPLL] = "top_audpll",
+	[MT2701_AUD_AUDPLL_D4] = "top_audpll_d4",
+	[MT2701_AUD_AUDPLL_D8] = "top_audpll_d8",
+	[MT2701_AUD_AUDPLL_D16] = "top_audpll_d16",
+	[MT2701_AUD_AUDPLL_D24] = "top_audpll_d24",
+	[MT2701_AUD_AUDINTBUS] = "top_audintbus_sel",
+	[MT2701_AUD_CLK_26M] = "clk_26m",
+	[MT2701_AUD_SYSPLL1_D4] = "top_syspll1_d4",
+	[MT2701_AUD_AUD_K1_SRC_SEL] = "top_aud_k1_src_sel",
+	[MT2701_AUD_AUD_K2_SRC_SEL] = "top_aud_k2_src_sel",
+	[MT2701_AUD_AUD_K3_SRC_SEL] = "top_aud_k3_src_sel",
+	[MT2701_AUD_AUD_K4_SRC_SEL] = "top_aud_k4_src_sel",
+	[MT2701_AUD_AUD_K5_SRC_SEL] = "top_aud_k5_src_sel",
+	[MT2701_AUD_AUD_K6_SRC_SEL] = "top_aud_k6_src_sel",
+	[MT2701_AUD_AUD_K1_SRC_DIV] = "top_aud_k1_src_div",
+	[MT2701_AUD_AUD_K2_SRC_DIV] = "top_aud_k2_src_div",
+	[MT2701_AUD_AUD_K3_SRC_DIV] = "top_aud_k3_src_div",
+	[MT2701_AUD_AUD_K4_SRC_DIV] = "top_aud_k4_src_div",
+	[MT2701_AUD_AUD_K5_SRC_DIV] = "top_aud_k5_src_div",
+	[MT2701_AUD_AUD_K6_SRC_DIV] = "top_aud_k6_src_div",
+	[MT2701_AUD_AUD_I2S1_MCLK] = "top_aud_i2s1_mclk",
+	[MT2701_AUD_AUD_I2S2_MCLK] = "top_aud_i2s2_mclk",
+	[MT2701_AUD_AUD_I2S3_MCLK] = "top_aud_i2s3_mclk",
+	[MT2701_AUD_AUD_I2S4_MCLK] = "top_aud_i2s4_mclk",
+	[MT2701_AUD_AUD_I2S5_MCLK] = "top_aud_i2s5_mclk",
+	[MT2701_AUD_AUD_I2S6_MCLK] = "top_aud_i2s6_mclk",
+	[MT2701_AUD_ASM_M_SEL] = "top_asm_m_sel",
+	[MT2701_AUD_ASM_H_SEL] = "top_asm_h_sel",
+	[MT2701_AUD_UNIVPLL2_D4] = "top_univpll2_d4",
+	[MT2701_AUD_UNIVPLL2_D2] = "top_univpll2_d2",
+	[MT2701_AUD_SYSPLL_D5] = "top_syspll_d5",
+};
+
+int mt2701_init_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int i = 0;
+
+	for (i = 0; i < MT2701_CLOCK_NUM; i++) {
+		afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
+		if (IS_ERR(aud_clks[i])) {
+			dev_warn(afe->dev, "%s devm_clk_get %s fail\n",
+				 __func__, aud_clks[i]);
+			return PTR_ERR(aud_clks[i]);
+		}
+	}
+
+	return 0;
+}
+
+int mt2701_afe_enable_clock(struct mtk_base_afe *afe)
+{
+	int ret = 0;
+
+	ret = mt2701_turn_on_a1sys_clock(afe);
+	if (ret) {
+		dev_err(afe->dev, "%s turn_on_a1sys_clock fail %d\n",
+			__func__, ret);
+		return ret;
+	}
+
+	ret = mt2701_turn_on_a2sys_clock(afe);
+	if (ret) {
+		dev_err(afe->dev, "%s turn_on_a2sys_clock fail %d\n",
+			__func__, ret);
+		mt2701_turn_off_a1sys_clock(afe);
+		return ret;
+	}
+
+	ret = mt2701_turn_on_afe_clock(afe);
+	if (ret) {
+		dev_err(afe->dev, "%s turn_on_afe_clock fail %d\n",
+			__func__, ret);
+		mt2701_turn_off_a1sys_clock(afe);
+		mt2701_turn_off_a2sys_clock(afe);
+		return ret;
+	}
+
+	regmap_update_bits(afe->regmap, ASYS_TOP_CON,
+			   AUDIO_TOP_CON0_A1SYS_A2SYS_ON,
+			   AUDIO_TOP_CON0_A1SYS_A2SYS_ON);
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+			   AFE_DAC_CON0_AFE_ON,
+			   AFE_DAC_CON0_AFE_ON);
+	regmap_write(afe->regmap, PWR2_TOP_CON,
+		     PWR2_TOP_CON_INIT_VAL);
+	regmap_write(afe->regmap, PWR1_ASM_CON1,
+		     PWR1_ASM_CON1_INIT_VAL);
+	regmap_write(afe->regmap, PWR2_ASM_CON1,
+		     PWR2_ASM_CON1_INIT_VAL);
+
+	return 0;
+}
+
+void mt2701_afe_disable_clock(struct mtk_base_afe *afe)
+{
+	mt2701_turn_off_afe_clock(afe);
+	mt2701_turn_off_a1sys_clock(afe);
+	mt2701_turn_off_a2sys_clock(afe);
+	regmap_update_bits(afe->regmap, ASYS_TOP_CON,
+			   AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0);
+	regmap_update_bits(afe->regmap, AFE_DAC_CON0,
+			   AFE_DAC_CON0_AFE_ON, 0);
+}
+
+int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int ret = 0;
+
+	/* Set Mux */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret);
+		goto A1SYS_CLK_AUD_MUX1_SEL_ERR;
+	}
+
+	ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL],
+			     afe_priv->clocks[MT2701_AUD_AUD1PLL_98M]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
+			aud_clks[MT2701_AUD_AUD_MUX1_SEL],
+			aud_clks[MT2701_AUD_AUD1PLL_98M], ret);
+		goto A1SYS_CLK_AUD_MUX1_SEL_ERR;
+	}
+
+	/* Set Divider */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__,
+			aud_clks[MT2701_AUD_AUD_MUX1_DIV],
+			ret);
+		goto A1SYS_CLK_AUD_MUX1_DIV_ERR;
+	}
+
+	ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV],
+			   MT2701_AUD_AUD_MUX1_DIV_RATE);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__,
+			aud_clks[MT2701_AUD_AUD_MUX1_DIV],
+			MT2701_AUD_AUD_MUX1_DIV_RATE, ret);
+		goto A1SYS_CLK_AUD_MUX1_DIV_ERR;
+	}
+
+	/* Enable clock gate */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_AUD_48K_TIMING], ret);
+		goto A1SYS_CLK_AUD_48K_ERR;
+	}
+
+	/* Enable infra audio */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
+		goto A1SYS_CLK_INFRA_ERR;
+	}
+
+	return 0;
+
+A1SYS_CLK_INFRA_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+A1SYS_CLK_AUD_48K_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
+A1SYS_CLK_AUD_MUX1_DIV_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
+A1SYS_CLK_AUD_MUX1_SEL_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
+
+	return ret;
+}
+
+void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
+}
+
+int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int ret = 0;
+
+	/* Set Mux */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret);
+		goto A2SYS_CLK_AUD_MUX2_SEL_ERR;
+	}
+
+	ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL],
+			     afe_priv->clocks[MT2701_AUD_AUD2PLL_90M]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
+			aud_clks[MT2701_AUD_AUD_MUX2_SEL],
+			aud_clks[MT2701_AUD_AUD2PLL_90M], ret);
+		goto A2SYS_CLK_AUD_MUX2_SEL_ERR;
+	}
+
+	/* Set Divider */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_AUD_MUX2_DIV], ret);
+		goto A2SYS_CLK_AUD_MUX2_DIV_ERR;
+	}
+
+	ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV],
+			   MT2701_AUD_AUD_MUX2_DIV_RATE);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__,
+			aud_clks[MT2701_AUD_AUD_MUX2_DIV],
+			MT2701_AUD_AUD_MUX2_DIV_RATE, ret);
+		goto A2SYS_CLK_AUD_MUX2_DIV_ERR;
+	}
+
+	/* Enable clock gate */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_AUD_44K_TIMING], ret);
+		goto A2SYS_CLK_AUD_44K_ERR;
+	}
+
+	/* Enable infra audio */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
+		goto A2SYS_CLK_INFRA_ERR;
+	}
+
+	return 0;
+
+A2SYS_CLK_INFRA_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+A2SYS_CLK_AUD_44K_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
+A2SYS_CLK_AUD_MUX2_DIV_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
+A2SYS_CLK_AUD_MUX2_SEL_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
+
+	return ret;
+}
+
+void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
+}
+
+int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+
+	/* enable INFRA_SYS */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret);
+		goto AFE_AUD_INFRA_ERR;
+	}
+
+	/* Set MT2701_AUD_AUDINTBUS to MT2701_AUD_SYSPLL1_D4 */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_AUDINTBUS], ret);
+		goto AFE_AUD_AUDINTBUS_ERR;
+	}
+
+	ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUDINTBUS],
+			     afe_priv->clocks[MT2701_AUD_SYSPLL1_D4]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
+			aud_clks[MT2701_AUD_AUDINTBUS],
+			aud_clks[MT2701_AUD_SYSPLL1_D4], ret);
+		goto AFE_AUD_AUDINTBUS_ERR;
+	}
+
+	/* Set MT2701_AUD_ASM_H_SEL to MT2701_AUD_UNIVPLL2_D2 */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_ASM_H_SEL], ret);
+		goto AFE_AUD_ASM_H_ERR;
+	}
+
+	ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_H_SEL],
+			     afe_priv->clocks[MT2701_AUD_UNIVPLL2_D2]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
+			aud_clks[MT2701_AUD_ASM_H_SEL],
+			aud_clks[MT2701_AUD_UNIVPLL2_D2], ret);
+		goto AFE_AUD_ASM_H_ERR;
+	}
+
+	/* Set MT2701_AUD_ASM_M_SEL to MT2701_AUD_UNIVPLL2_D4 */
+	ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[MT2701_AUD_ASM_M_SEL], ret);
+		goto AFE_AUD_ASM_M_ERR;
+	}
+
+	ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_M_SEL],
+			     afe_priv->clocks[MT2701_AUD_UNIVPLL2_D4]);
+	if (ret) {
+		dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__,
+			aud_clks[MT2701_AUD_ASM_M_SEL],
+			aud_clks[MT2701_AUD_UNIVPLL2_D4], ret);
+		goto AFE_AUD_ASM_M_ERR;
+	}
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+			   AUDIO_TOP_CON0_PDN_AFE, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+			   AUDIO_TOP_CON0_PDN_APLL_CK, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_A1SYS, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_A2SYS, 0);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_AFE_CONN, 0);
+
+	return 0;
+
+AFE_AUD_ASM_M_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
+AFE_AUD_ASM_H_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
+AFE_AUD_AUDINTBUS_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
+AFE_AUD_INFRA_ERR:
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+
+	return ret;
+}
+
+void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]);
+
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]);
+	clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]);
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+			   AUDIO_TOP_CON0_PDN_AFE, AUDIO_TOP_CON0_PDN_AFE);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
+			   AUDIO_TOP_CON0_PDN_APLL_CK,
+			   AUDIO_TOP_CON0_PDN_APLL_CK);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_A1SYS,
+			   AUDIO_TOP_CON4_PDN_A1SYS);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_A2SYS,
+			   AUDIO_TOP_CON4_PDN_A2SYS);
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_AFE_CONN,
+			   AUDIO_TOP_CON4_PDN_AFE_CONN);
+}
+
+void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
+			       int mclk)
+{
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+	int ret;
+	int aud_src_div_id = MT2701_AUD_AUD_K1_SRC_DIV + id;
+	int aud_src_clk_id = MT2701_AUD_AUD_K1_SRC_SEL + id;
+
+	/* Set MCLK Kx_SRC_SEL(domain) */
+	ret = clk_prepare_enable(afe_priv->clocks[aud_src_clk_id]);
+	if (ret)
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[aud_src_clk_id], ret);
+
+	if (domain == 0) {
+		ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id],
+				     afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]);
+		if (ret)
+			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+				__func__, aud_clks[aud_src_clk_id],
+				aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret);
+	} else {
+		ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id],
+				     afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]);
+		if (ret)
+			dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n",
+				__func__, aud_clks[aud_src_clk_id],
+				aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret);
+	}
+	clk_disable_unprepare(afe_priv->clocks[aud_src_clk_id]);
+
+	/* Set MCLK Kx_SRC_DIV(divider) */
+	ret = clk_prepare_enable(afe_priv->clocks[aud_src_div_id]);
+	if (ret)
+		dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n",
+			__func__, aud_clks[aud_src_div_id], ret);
+
+	ret = clk_set_rate(afe_priv->clocks[aud_src_div_id], mclk);
+	if (ret)
+		dev_err(afe->dev, "%s clk_set_rate %s-%d fail %d\n", __func__,
+			aud_clks[aud_src_div_id], mclk, ret);
+	clk_disable_unprepare(afe_priv->clocks[aud_src_div_id]);
+}
+
+MODULE_DESCRIPTION("MT2701 afe clock control");
+MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
new file mode 100644
index 0000000..6497d57
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h
@@ -0,0 +1,38 @@
+/*
+ * mt2701-afe-clock-ctrl.h  --  Mediatek 2701 afe clock ctrl definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _MT2701_AFE_CLOCK_CTRL_H_
+#define _MT2701_AFE_CLOCK_CTRL_H_
+
+struct mtk_base_afe;
+
+int mt2701_init_clock(struct mtk_base_afe *afe);
+int mt2701_afe_enable_clock(struct mtk_base_afe *afe);
+void mt2701_afe_disable_clock(struct mtk_base_afe *afe);
+
+int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe);
+void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe);
+
+int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe);
+void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe);
+
+int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe);
+void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe);
+
+void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain,
+			       int mclk);
+
+#endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
new file mode 100644
index 0000000..c77166e
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h
@@ -0,0 +1,181 @@
+/*
+ * mt2701-afe-common.h  --  Mediatek 2701 audio driver definitions
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _MT_2701_AFE_COMMON_H_
+#define _MT_2701_AFE_COMMON_H_
+#include <sound/soc.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include "mt2701-reg.h"
+#include "../common/mtk-base-afe.h"
+
+#define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1)
+#define MT2701_PLL_DOMAIN_0_RATE	98304000
+#define MT2701_PLL_DOMAIN_1_RATE	90316800
+#define MT2701_AUD_AUD_MUX1_DIV_RATE (MT2701_PLL_DOMAIN_0_RATE / 2)
+#define MT2701_AUD_AUD_MUX2_DIV_RATE (MT2701_PLL_DOMAIN_1_RATE / 2)
+
+enum {
+	MT2701_I2S_1,
+	MT2701_I2S_2,
+	MT2701_I2S_3,
+	MT2701_I2S_4,
+	MT2701_I2S_NUM,
+};
+
+enum {
+	MT2701_MEMIF_DL1,
+	MT2701_MEMIF_DL2,
+	MT2701_MEMIF_DL3,
+	MT2701_MEMIF_DL4,
+	MT2701_MEMIF_DL5,
+	MT2701_MEMIF_DL_SINGLE_NUM,
+	MT2701_MEMIF_DLM = MT2701_MEMIF_DL_SINGLE_NUM,
+	MT2701_MEMIF_UL1,
+	MT2701_MEMIF_UL2,
+	MT2701_MEMIF_UL3,
+	MT2701_MEMIF_UL4,
+	MT2701_MEMIF_UL5,
+	MT2701_MEMIF_DLBT,
+	MT2701_MEMIF_ULBT,
+	MT2701_MEMIF_NUM,
+	MT2701_IO_I2S = MT2701_MEMIF_NUM,
+	MT2701_IO_2ND_I2S,
+	MT2701_IO_3RD_I2S,
+	MT2701_IO_4TH_I2S,
+	MT2701_IO_5TH_I2S,
+	MT2701_IO_6TH_I2S,
+	MT2701_IO_MRG,
+};
+
+enum {
+	MT2701_IRQ_ASYS_START,
+	MT2701_IRQ_ASYS_IRQ1 = MT2701_IRQ_ASYS_START,
+	MT2701_IRQ_ASYS_IRQ2,
+	MT2701_IRQ_ASYS_IRQ3,
+	MT2701_IRQ_ASYS_END,
+};
+
+enum {
+	DIV_ID_MCLK_TO_BCK,
+	DIV_ID_BCK_TO_LRCK,
+};
+
+/* 2701 clock def */
+enum audio_system_clock_type {
+	MT2701_AUD_INFRA_SYS_AUDIO,
+	MT2701_AUD_AUD_MUX1_SEL,
+	MT2701_AUD_AUD_MUX2_SEL,
+	MT2701_AUD_AUD_MUX1_DIV,
+	MT2701_AUD_AUD_MUX2_DIV,
+	MT2701_AUD_AUD_48K_TIMING,
+	MT2701_AUD_AUD_44K_TIMING,
+	MT2701_AUD_AUDPLL_MUX_SEL,
+	MT2701_AUD_APLL_SEL,
+	MT2701_AUD_AUD1PLL_98M,
+	MT2701_AUD_AUD2PLL_90M,
+	MT2701_AUD_HADDS2PLL_98M,
+	MT2701_AUD_HADDS2PLL_294M,
+	MT2701_AUD_AUDPLL,
+	MT2701_AUD_AUDPLL_D4,
+	MT2701_AUD_AUDPLL_D8,
+	MT2701_AUD_AUDPLL_D16,
+	MT2701_AUD_AUDPLL_D24,
+	MT2701_AUD_AUDINTBUS,
+	MT2701_AUD_CLK_26M,
+	MT2701_AUD_SYSPLL1_D4,
+	MT2701_AUD_AUD_K1_SRC_SEL,
+	MT2701_AUD_AUD_K2_SRC_SEL,
+	MT2701_AUD_AUD_K3_SRC_SEL,
+	MT2701_AUD_AUD_K4_SRC_SEL,
+	MT2701_AUD_AUD_K5_SRC_SEL,
+	MT2701_AUD_AUD_K6_SRC_SEL,
+	MT2701_AUD_AUD_K1_SRC_DIV,
+	MT2701_AUD_AUD_K2_SRC_DIV,
+	MT2701_AUD_AUD_K3_SRC_DIV,
+	MT2701_AUD_AUD_K4_SRC_DIV,
+	MT2701_AUD_AUD_K5_SRC_DIV,
+	MT2701_AUD_AUD_K6_SRC_DIV,
+	MT2701_AUD_AUD_I2S1_MCLK,
+	MT2701_AUD_AUD_I2S2_MCLK,
+	MT2701_AUD_AUD_I2S3_MCLK,
+	MT2701_AUD_AUD_I2S4_MCLK,
+	MT2701_AUD_AUD_I2S5_MCLK,
+	MT2701_AUD_AUD_I2S6_MCLK,
+	MT2701_AUD_ASM_M_SEL,
+	MT2701_AUD_ASM_H_SEL,
+	MT2701_AUD_UNIVPLL2_D4,
+	MT2701_AUD_UNIVPLL2_D2,
+	MT2701_AUD_SYSPLL_D5,
+	MT2701_CLOCK_NUM
+};
+
+static const unsigned int mt2701_afe_backup_list[] = {
+	AUDIO_TOP_CON0,
+	AUDIO_TOP_CON4,
+	AUDIO_TOP_CON5,
+	ASYS_TOP_CON,
+	AFE_CONN0,
+	AFE_CONN1,
+	AFE_CONN2,
+	AFE_CONN3,
+	AFE_CONN15,
+	AFE_CONN16,
+	AFE_CONN17,
+	AFE_CONN18,
+	AFE_CONN19,
+	AFE_CONN20,
+	AFE_CONN21,
+	AFE_CONN22,
+	AFE_DAC_CON0,
+	AFE_MEMIF_PBUF_SIZE,
+};
+
+struct snd_pcm_substream;
+struct mtk_base_irq_data;
+
+struct mt2701_i2s_data {
+	int i2s_ctrl_reg;
+	int i2s_pwn_shift;
+	int i2s_asrc_fs_shift;
+	int i2s_asrc_fs_mask;
+};
+
+enum mt2701_i2s_dir {
+	I2S_OUT,
+	I2S_IN,
+	I2S_DIR_NUM,
+};
+
+struct mt2701_i2s_path {
+	int dai_id;
+	int mclk_rate;
+	int div_mclk_to_bck;
+	int div_bck_to_lrck;
+	int format;
+	snd_pcm_format_t stream_fmt;
+	int on[I2S_DIR_NUM];
+	int occupied[I2S_DIR_NUM];
+	const struct mt2701_i2s_data *i2s_data[2];
+};
+
+struct mt2701_afe_private {
+	struct clk *clocks[MT2701_CLOCK_NUM];
+	struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM];
+	bool mrg_enable[MT2701_STREAM_DIR_NUM];
+};
+
+#endif
diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h
new file mode 100644
index 0000000..bb62b1c
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-reg.h
@@ -0,0 +1,186 @@
+/*
+ * mt2701-reg.h  --  Mediatek 2701 audio driver reg definition
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _MT2701_REG_H_
+#define _MT2701_REG_H_
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include "mt2701-afe-common.h"
+
+/*****************************************************************************
+ *                  R E G I S T E R       D E F I N I T I O N
+ *****************************************************************************/
+#define AUDIO_TOP_CON0 0x0000
+#define AUDIO_TOP_CON4 0x0010
+#define AUDIO_TOP_CON5 0x0014
+#define AFE_DAIBT_CON0 0x001c
+#define AFE_MRGIF_CON 0x003c
+#define ASMI_TIMING_CON1 0x0100
+#define ASMO_TIMING_CON1 0x0104
+#define PWR1_ASM_CON1 0x0108
+#define ASYS_TOP_CON 0x0600
+#define ASYS_I2SIN1_CON 0x0604
+#define ASYS_I2SIN2_CON 0x0608
+#define ASYS_I2SIN3_CON 0x060c
+#define ASYS_I2SIN4_CON 0x0610
+#define ASYS_I2SIN5_CON 0x0614
+#define ASYS_I2SO1_CON 0x061C
+#define ASYS_I2SO2_CON 0x0620
+#define ASYS_I2SO3_CON 0x0624
+#define ASYS_I2SO4_CON 0x0628
+#define ASYS_I2SO5_CON 0x062c
+#define PWR2_TOP_CON 0x0634
+#define AFE_CONN0 0x06c0
+#define AFE_CONN1 0x06c4
+#define AFE_CONN2 0x06c8
+#define AFE_CONN3 0x06cc
+#define AFE_CONN14 0x06f8
+#define AFE_CONN15 0x06fc
+#define AFE_CONN16 0x0700
+#define AFE_CONN17 0x0704
+#define AFE_CONN18 0x0708
+#define AFE_CONN19 0x070c
+#define AFE_CONN20 0x0710
+#define AFE_CONN21 0x0714
+#define AFE_CONN22 0x0718
+#define AFE_CONN23 0x071c
+#define AFE_CONN24 0x0720
+#define AFE_CONN41 0x0764
+#define ASYS_IRQ1_CON 0x0780
+#define ASYS_IRQ2_CON 0x0784
+#define ASYS_IRQ3_CON 0x0788
+#define ASYS_IRQ_CLR 0x07c0
+#define ASYS_IRQ_STATUS 0x07c4
+#define PWR2_ASM_CON1 0x1070
+#define AFE_DAC_CON0 0x1200
+#define AFE_DAC_CON1 0x1204
+#define AFE_DAC_CON2 0x1208
+#define AFE_DAC_CON3 0x120c
+#define AFE_DAC_CON4 0x1210
+#define AFE_MEMIF_HD_CON1 0x121c
+#define AFE_MEMIF_PBUF_SIZE 0x1238
+#define AFE_MEMIF_HD_CON0 0x123c
+#define AFE_DL1_BASE 0x1240
+#define AFE_DL1_CUR 0x1244
+#define AFE_DL2_BASE 0x1250
+#define AFE_DL2_CUR 0x1254
+#define AFE_DL3_BASE 0x1260
+#define AFE_DL3_CUR 0x1264
+#define AFE_DL4_BASE 0x1270
+#define AFE_DL4_CUR 0x1274
+#define AFE_DL5_BASE 0x1280
+#define AFE_DL5_CUR 0x1284
+#define AFE_DLMCH_BASE 0x12a0
+#define AFE_DLMCH_CUR 0x12a4
+#define AFE_ARB1_BASE 0x12b0
+#define AFE_ARB1_CUR 0x12b4
+#define AFE_VUL_BASE 0x1300
+#define AFE_VUL_CUR 0x130c
+#define AFE_UL2_BASE 0x1310
+#define AFE_UL2_END 0x1318
+#define AFE_UL2_CUR 0x131c
+#define AFE_UL3_BASE 0x1320
+#define AFE_UL3_END 0x1328
+#define AFE_UL3_CUR 0x132c
+#define AFE_UL4_BASE 0x1330
+#define AFE_UL4_END 0x1338
+#define AFE_UL4_CUR 0x133c
+#define AFE_UL5_BASE 0x1340
+#define AFE_UL5_END 0x1348
+#define AFE_UL5_CUR 0x134c
+#define AFE_DAI_BASE 0x1370
+#define AFE_DAI_CUR 0x137c
+
+/* AUDIO_TOP_CON0 (0x0000) */
+#define AUDIO_TOP_CON0_A1SYS_A2SYS_ON	(0x3 << 0)
+#define AUDIO_TOP_CON0_PDN_AFE		(0x1 << 2)
+#define AUDIO_TOP_CON0_PDN_APLL_CK	(0x1 << 23)
+
+/* AUDIO_TOP_CON4 (0x0010) */
+#define AUDIO_TOP_CON4_I2SO1_PWN	(0x1 << 6)
+#define AUDIO_TOP_CON4_PDN_A1SYS	(0x1 << 21)
+#define AUDIO_TOP_CON4_PDN_A2SYS	(0x1 << 22)
+#define AUDIO_TOP_CON4_PDN_AFE_CONN	(0x1 << 23)
+#define AUDIO_TOP_CON4_PDN_MRGIF	(0x1 << 25)
+
+/* AFE_DAIBT_CON0 (0x001c) */
+#define AFE_DAIBT_CON0_DAIBT_EN		(0x1 << 0)
+#define AFE_DAIBT_CON0_BT_FUNC_EN	(0x1 << 1)
+#define AFE_DAIBT_CON0_BT_FUNC_RDY	(0x1 << 3)
+#define AFE_DAIBT_CON0_BT_WIDE_MODE_EN	(0x1 << 9)
+#define AFE_DAIBT_CON0_MRG_USE		(0x1 << 12)
+
+/* PWR1_ASM_CON1 (0x0108) */
+#define PWR1_ASM_CON1_INIT_VAL		(0x492)
+
+/* AFE_MRGIF_CON (0x003c) */
+#define AFE_MRGIF_CON_MRG_EN		(0x1 << 0)
+#define AFE_MRGIF_CON_MRG_I2S_EN	(0x1 << 16)
+#define AFE_MRGIF_CON_I2S_MODE_MASK	(0xf << 20)
+#define AFE_MRGIF_CON_I2S_MODE_32K	(0x4 << 20)
+
+/* ASYS_I2SO1_CON (0x061c) */
+#define ASYS_I2SO1_CON_FS		(0x1f << 8)
+#define ASYS_I2SO1_CON_FS_SET(x)	((x) << 8)
+#define ASYS_I2SO1_CON_MULTI_CH		(0x1 << 16)
+#define ASYS_I2SO1_CON_SIDEGEN		(0x1 << 30)
+#define ASYS_I2SO1_CON_I2S_EN		(0x1 << 0)
+/* 0:EIAJ 1:I2S */
+#define ASYS_I2SO1_CON_I2S_MODE		(0x1 << 3)
+#define ASYS_I2SO1_CON_WIDE_MODE	(0x1 << 1)
+#define ASYS_I2SO1_CON_WIDE_MODE_SET(x)	((x) << 1)
+
+/* PWR2_TOP_CON (0x0634) */
+#define PWR2_TOP_CON_INIT_VAL		(0xffe1ffff)
+
+/* ASYS_IRQ_CLR (0x07c0) */
+#define ASYS_IRQ_CLR_ALL		(0xffffffff)
+
+/* PWR2_ASM_CON1 (0x1070) */
+#define PWR2_ASM_CON1_INIT_VAL		(0x492492)
+
+/* AFE_DAC_CON0 (0x1200) */
+#define AFE_DAC_CON0_AFE_ON		(0x1 << 0)
+
+/* AFE_MEMIF_PBUF_SIZE (0x1238) */
+#define AFE_MEMIF_PBUF_SIZE_DLM_MASK		(0x1 << 29)
+#define AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE	(0x0 << 29)
+#define AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE	(0x1 << 29)
+#define DLMCH_BIT_WIDTH_MASK			(0x1 << 28)
+#define AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK		(0xf << 24)
+#define AFE_MEMIF_PBUF_SIZE_DLM_CH(x)		((x) << 24)
+#define AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK	(0x3 << 12)
+#define AFE_MEMIF_PBUF_SIZE_DLM_32BYTES		(0x1 << 12)
+
+/* I2S in/out register bit control */
+#define ASYS_I2S_CON_FS			(0x1f << 8)
+#define ASYS_I2S_CON_FS_SET(x)		((x) << 8)
+#define ASYS_I2S_CON_RESET		(0x1 << 30)
+#define ASYS_I2S_CON_I2S_EN		(0x1 << 0)
+#define ASYS_I2S_CON_I2S_COUPLE_MODE	(0x1 << 17)
+/* 0:EIAJ 1:I2S */
+#define ASYS_I2S_CON_I2S_MODE		(0x1 << 3)
+#define ASYS_I2S_CON_WIDE_MODE		(0x1 << 1)
+#define ASYS_I2S_CON_WIDE_MODE_SET(x)	((x) << 1)
+#define ASYS_I2S_IN_PHASE_FIX		(0x1 << 31)
+
+#define AFE_END_ADDR 0x15e0
+#endif
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1424759 — [alsa-devel] [PATCH v5 8/9] ASoC: mediatek: add BT implementation

FromGarlic Tseng <garlic.tseng@mediatek.com>
Date2016-06-17 09:50 +0200
Subject[alsa-devel] [PATCH v5 8/9] ASoC: mediatek: add BT implementation
Message-ID<rKWHo-3Cb-31@gated-at.bofh.it>
In reply to#1424755
Add BT implementation for mt2701 platform driver.

Signed-off-by: Garlic Tseng <garlic.tseng@mediatek.com>
---
 sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | 139 +++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
index deb5f82..5fd2caa 100644
--- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
+++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c
@@ -377,6 +377,86 @@ static int mt2701_afe_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	return 0;
 }
 
+static int mt2701_btmrg_startup(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+			   AUDIO_TOP_CON4_PDN_MRGIF, 0);
+
+	afe_priv->mrg_enable[substream->stream] = 1;
+	return 0;
+}
+
+static int mt2701_btmrg_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 mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	int stream_fs;
+	u32 val, msk;
+
+	stream_fs = params_rate(params);
+
+	if ((stream_fs != 8000) && (stream_fs != 16000)) {
+		dev_err(afe->dev, "%s() btmgr not supprt this stream_fs %d\n",
+			__func__, stream_fs);
+		return -EINVAL;
+	}
+
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_I2S_MODE_MASK,
+			   AFE_MRGIF_CON_I2S_MODE_32K);
+
+	val = AFE_DAIBT_CON0_BT_FUNC_EN | AFE_DAIBT_CON0_BT_FUNC_RDY
+	      | AFE_DAIBT_CON0_MRG_USE;
+	msk = val;
+
+	if (stream_fs == 16000)
+		val |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+	msk |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN;
+
+	regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, msk, val);
+
+	regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+			   AFE_DAIBT_CON0_DAIBT_EN,
+			   AFE_DAIBT_CON0_DAIBT_EN);
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_MRG_I2S_EN,
+			   AFE_MRGIF_CON_MRG_I2S_EN);
+	regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+			   AFE_MRGIF_CON_MRG_EN,
+			   AFE_MRGIF_CON_MRG_EN);
+	return 0;
+}
+
+static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream,
+				  struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt2701_afe_private *afe_priv = afe->platform_priv;
+
+	/* if the other direction stream is not occupied */
+	if (!afe_priv->mrg_enable[!substream->stream]) {
+		regmap_update_bits(afe->regmap, AFE_DAIBT_CON0,
+				   AFE_DAIBT_CON0_DAIBT_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+				   AFE_MRGIF_CON_MRG_EN, 0);
+		regmap_update_bits(afe->regmap, AFE_MRGIF_CON,
+				   AFE_MRGIF_CON_MRG_I2S_EN, 0);
+		regmap_update_bits(afe->regmap, AUDIO_TOP_CON4,
+				   AUDIO_TOP_CON4_PDN_MRGIF,
+				   AUDIO_TOP_CON4_PDN_MRGIF);
+	}
+	afe_priv->mrg_enable[substream->stream] = 0;
+}
+
 static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
@@ -560,6 +640,13 @@ static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = {
 	.set_fmt	= mt2701_afe_i2s_set_fmt,
 };
 
+/* MRG BE DAIs */
+static struct snd_soc_dai_ops mt2701_btmrg_ops = {
+	.startup = mt2701_btmrg_startup,
+	.shutdown = mt2701_btmrg_shutdown,
+	.hw_params = mt2701_btmrg_hw_params,
+};
+
 static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 	/* FE DAIs: memory intefaces to CPU */
 	{
@@ -610,6 +697,36 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		},
 		.ops = &mt2701_single_memif_dai_ops,
 	},
+	{
+		.name = "PCM_BT_DL",
+		.id = MT2701_MEMIF_DLBT,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.playback = {
+			.stream_name = "DLBT",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
+	{
+		.name = "PCM_BT_UL",
+		.id = MT2701_MEMIF_ULBT,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
+		.capture = {
+			.stream_name = "ULBT",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_single_memif_dai_ops,
+	},
 	/* BE DAIs */
 	{
 		.name = "I2S0",
@@ -709,6 +826,28 @@ static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = {
 		.ops = &mt2701_afe_i2s_ops,
 		.symmetric_rates = 1,
 	},
+	{
+		.name = "MRG BT",
+		.id = MT2701_IO_MRG,
+		.playback = {
+			.stream_name = "BT Playback",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.capture = {
+			.stream_name = "BT Capture",
+			.channels_min = 1,
+			.channels_max = 1,
+			.rates = (SNDRV_PCM_RATE_8000
+				| SNDRV_PCM_RATE_16000),
+			.formats = SNDRV_PCM_FMTBIT_S16_LE,
+		},
+		.ops = &mt2701_btmrg_ops,
+		.symmetric_rates = 1,
+	}
 };
 
 static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = {
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1424761 — [alsa-devel] [PATCH v5 3/9] ASoC: mediatek: let mt8173 use mediatek common structure

FromGarlic Tseng <garlic.tseng@mediatek.com>
Date2016-06-17 09:50 +0200
Subject[alsa-devel] [PATCH v5 3/9] ASoC: mediatek: let mt8173 use mediatek common structure
Message-ID<rKWHo-3Cb-43@gated-at.bofh.it>
In reply to#1424755
Modify mt8173 driver implementation to use common structure.

Signed-off-by: Garlic Tseng <garlic.tseng@mediatek.com>
---
 sound/soc/mediatek/Kconfig                    |   4 +
 sound/soc/mediatek/Makefile                   |   2 +-
 sound/soc/mediatek/common/Makefile            |  16 +
 sound/soc/mediatek/mt8173/mt8173-afe-common.h |  42 +-
 sound/soc/mediatek/mt8173/mt8173-afe-pcm.c    | 679 +++++++++++---------------
 5 files changed, 318 insertions(+), 425 deletions(-)
 create mode 100644 sound/soc/mediatek/common/Makefile

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index ae9f664..705904b 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -1,6 +1,10 @@
+config SND_SOC_MEDIATEK
+	tristate
+
 config SND_SOC_MT8173
 	tristate "ASoC support for Mediatek MT8173 chip"
 	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
 	help
 	  This adds ASoC platform driver support for Mediatek MT8173 chip
 	  that can be used with other codecs.
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 240dfc70..4fe8068 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,2 +1,2 @@
-# 8173 Machine support
+obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile
new file mode 100644
index 0000000..a55d33b
--- /dev/null
+++ b/sound/soc/mediatek/common/Makefile
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2015 MediaTek Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# 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.
+#
+
+# platform driver
+snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o
+obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-common.h b/sound/soc/mediatek/mt8173/mt8173-afe-common.h
index 8f2936d..9a4837c 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-common.h
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-common.h
@@ -46,14 +46,13 @@ enum {
 };
 
 enum {
-	MT8173_AFE_IRQ_1,
-	MT8173_AFE_IRQ_2,
-	MT8173_AFE_IRQ_3,
-	MT8173_AFE_IRQ_4,
-	MT8173_AFE_IRQ_5,
-	MT8173_AFE_IRQ_6,
-	MT8173_AFE_IRQ_7,
-	MT8173_AFE_IRQ_8,
+	MT8173_AFE_IRQ_DL1,
+	MT8173_AFE_IRQ_DL2,
+	MT8173_AFE_IRQ_VUL,
+	MT8173_AFE_IRQ_DAI,
+	MT8173_AFE_IRQ_AWB,
+	MT8173_AFE_IRQ_MOD_DAI,
+	MT8173_AFE_IRQ_HDMI,
 	MT8173_AFE_IRQ_NUM,
 };
 
@@ -71,31 +70,4 @@ enum {
 	MT8173_CLK_NUM
 };
 
-struct mt8173_afe;
-struct snd_pcm_substream;
-
-struct mt8173_afe_memif_data {
-	int id;
-	const char *name;
-	int reg_ofs_base;
-	int reg_ofs_cur;
-	int fs_shift;
-	int mono_shift;
-	int enable_shift;
-	int irq_reg_cnt;
-	int irq_cnt_shift;
-	int irq_en_shift;
-	int irq_fs_shift;
-	int irq_clr_shift;
-	int msb_shift;
-};
-
-struct mt8173_afe_memif {
-	unsigned int phys_buf_addr;
-	int buffer_size;
-	struct snd_pcm_substream *substream;
-	const struct mt8173_afe_memif_data *data;
-	const struct mt8173_afe_irq_data *irqdata;
-};
-
 #endif
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
index 4fc52bc..8a643a3 100644
--- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
+++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c
@@ -25,6 +25,9 @@
 #include <linux/pm_runtime.h>
 #include <sound/soc.h>
 #include "mt8173-afe-common.h"
+#include "../common/mtk-base-afe.h"
+#include "../common/mtk-afe-platform-driver.h"
+#include "../common/mtk-afe-fe-dai.h"
 
 /*****************************************************************************
  *                  R E G I S T E R       D E F I N I T I O N
@@ -81,7 +84,6 @@
 #define AFE_TDM_CON1		0x0548
 #define AFE_TDM_CON2		0x054c
 
-#define AFE_BASE_END_OFFSET	8
 #define AFE_IRQ_STATUS_BITS	0xff
 
 /* AUDIO_TOP_CON0 (0x0000) */
@@ -152,15 +154,8 @@ static const unsigned int mt8173_afe_backup_list[] = {
 	AFE_DAC_CON0,
 };
 
-struct mt8173_afe {
-	/* address for ioremap audio hardware register */
-	void __iomem *base_addr;
-	struct device *dev;
-	struct regmap *regmap;
-	struct mt8173_afe_memif memif[MT8173_AFE_MEMIF_NUM];
+struct mt8173_afe_private {
 	struct clk *clocks[MT8173_CLK_NUM];
-	unsigned int backup_regs[ARRAY_SIZE(mt8173_afe_backup_list)];
-	bool suspended;
 };
 
 static const struct snd_pcm_hardware mt8173_afe_hardware = {
@@ -174,53 +169,6 @@ static const struct snd_pcm_hardware mt8173_afe_hardware = {
 	.fifo_size = 0,
 };
 
-static snd_pcm_uframes_t mt8173_afe_pcm_pointer
-			 (struct snd_pcm_substream *substream)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-	struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
-	unsigned int hw_ptr;
-	int ret;
-
-	ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr);
-	if (ret || hw_ptr == 0) {
-		dev_err(afe->dev, "%s hw_ptr err\n", __func__);
-		hw_ptr = memif->phys_buf_addr;
-	}
-
-	return bytes_to_frames(substream->runtime,
-			       hw_ptr - memif->phys_buf_addr);
-}
-
-static const struct snd_pcm_ops mt8173_afe_pcm_ops = {
-	.ioctl = snd_pcm_lib_ioctl,
-	.pointer = mt8173_afe_pcm_pointer,
-};
-
-static int mt8173_afe_pcm_new(struct snd_soc_pcm_runtime *rtd)
-{
-	size_t size;
-	struct snd_card *card = rtd->card->snd_card;
-	struct snd_pcm *pcm = rtd->pcm;
-
-	size = mt8173_afe_hardware.buffer_bytes_max;
-
-	return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
-						     card->dev, size, size);
-}
-
-static void mt8173_afe_pcm_free(struct snd_pcm *pcm)
-{
-	snd_pcm_lib_preallocate_free_for_all(pcm);
-}
-
-static const struct snd_soc_platform_driver mt8173_afe_pcm_platform = {
-	.ops = &mt8173_afe_pcm_ops,
-	.pcm_new = mt8173_afe_pcm_new,
-	.pcm_free = mt8173_afe_pcm_free,
-};
-
 struct mt8173_afe_rate {
 	unsigned int rate;
 	unsigned int regvalue;
@@ -253,7 +201,7 @@ static int mt8173_afe_i2s_fs(unsigned int sample_rate)
 	return -EINVAL;
 }
 
-static int mt8173_afe_set_i2s(struct mt8173_afe *afe, unsigned int rate)
+static int mt8173_afe_set_i2s(struct mtk_base_afe *afe, unsigned int rate)
 {
 	unsigned int val;
 	int fs = mt8173_afe_i2s_fs(rate);
@@ -281,7 +229,7 @@ static int mt8173_afe_set_i2s(struct mt8173_afe *afe, unsigned int rate)
 	return 0;
 }
 
-static void mt8173_afe_set_i2s_enable(struct mt8173_afe *afe, bool enable)
+static void mt8173_afe_set_i2s_enable(struct mtk_base_afe *afe, bool enable)
 {
 	unsigned int val;
 
@@ -296,7 +244,7 @@ static void mt8173_afe_set_i2s_enable(struct mt8173_afe *afe, bool enable)
 	regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable);
 }
 
-static int mt8173_afe_dais_enable_clks(struct mt8173_afe *afe,
+static int mt8173_afe_dais_enable_clks(struct mtk_base_afe *afe,
 				       struct clk *m_ck, struct clk *b_ck)
 {
 	int ret;
@@ -319,7 +267,7 @@ static int mt8173_afe_dais_enable_clks(struct mt8173_afe *afe,
 	return 0;
 }
 
-static int mt8173_afe_dais_set_clks(struct mt8173_afe *afe,
+static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe,
 				    struct clk *m_ck, unsigned int mck_rate,
 				    struct clk *b_ck, unsigned int bck_rate)
 {
@@ -343,7 +291,7 @@ static int mt8173_afe_dais_set_clks(struct mt8173_afe *afe,
 	return 0;
 }
 
-static void mt8173_afe_dais_disable_clks(struct mt8173_afe *afe,
+static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe,
 					 struct clk *m_ck, struct clk *b_ck)
 {
 	if (m_ck)
@@ -356,7 +304,7 @@ static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream,
 				  struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
 
 	if (dai->active)
 		return 0;
@@ -370,7 +318,7 @@ static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream,
 				    struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
 
 	if (dai->active)
 		return;
@@ -386,12 +334,13 @@ static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 	int ret;
 
-	mt8173_afe_dais_set_clks(afe, afe->clocks[MT8173_CLK_I2S1_M],
+	mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S1_M],
 				 runtime->rate * 256, NULL, 0);
-	mt8173_afe_dais_set_clks(afe, afe->clocks[MT8173_CLK_I2S2_M],
+	mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S2_M],
 				 runtime->rate * 256, NULL, 0);
 	/* config I2S */
 	ret = mt8173_afe_set_i2s(afe, substream->runtime->rate);
@@ -407,13 +356,14 @@ static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream,
 				   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	if (dai->active)
 		return 0;
 
-	mt8173_afe_dais_enable_clks(afe, afe->clocks[MT8173_CLK_I2S3_M],
-				    afe->clocks[MT8173_CLK_I2S3_B]);
+	mt8173_afe_dais_enable_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M],
+				    afe_priv->clocks[MT8173_CLK_I2S3_B]);
 	return 0;
 }
 
@@ -421,13 +371,14 @@ static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream,
 				     struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	if (dai->active)
 		return;
 
-	mt8173_afe_dais_disable_clks(afe, afe->clocks[MT8173_CLK_I2S3_M],
-				     afe->clocks[MT8173_CLK_I2S3_B]);
+	mt8173_afe_dais_disable_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M],
+				     afe_priv->clocks[MT8173_CLK_I2S3_B]);
 }
 
 static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream,
@@ -435,12 +386,14 @@ static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream,
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
+
 	unsigned int val;
 
-	mt8173_afe_dais_set_clks(afe, afe->clocks[MT8173_CLK_I2S3_M],
+	mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M],
 				 runtime->rate * 128,
-				 afe->clocks[MT8173_CLK_I2S3_B],
+				 afe_priv->clocks[MT8173_CLK_I2S3_B],
 				 runtime->rate * runtime->channels * 32);
 
 	val = AFE_TDM_CON1_BCK_INV |
@@ -496,7 +449,7 @@ static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
 				   struct snd_soc_dai *dai)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
 
 	dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name);
 
@@ -508,10 +461,14 @@ static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
 
 		/* set connections:  O30~O37: L/R/LS/RS/C/LFE/CH7/CH8 */
 		regmap_write(afe->regmap, AFE_HDMI_CONN0,
-			     AFE_HDMI_CONN0_O30_I30 | AFE_HDMI_CONN0_O31_I31 |
-			     AFE_HDMI_CONN0_O32_I34 | AFE_HDMI_CONN0_O33_I35 |
-			     AFE_HDMI_CONN0_O34_I32 | AFE_HDMI_CONN0_O35_I33 |
-			     AFE_HDMI_CONN0_O36_I36 | AFE_HDMI_CONN0_O37_I37);
+				 AFE_HDMI_CONN0_O30_I30 |
+				 AFE_HDMI_CONN0_O31_I31 |
+				 AFE_HDMI_CONN0_O32_I34 |
+				 AFE_HDMI_CONN0_O33_I35 |
+				 AFE_HDMI_CONN0_O34_I32 |
+				 AFE_HDMI_CONN0_O35_I33 |
+				 AFE_HDMI_CONN0_O36_I36 |
+				 AFE_HDMI_CONN0_O37_I37);
 
 		/* enable Out control */
 		regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1);
@@ -531,224 +488,46 @@ static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd,
 		regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
 				   AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF,
 				   AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF);
-
 		return 0;
 	default:
 		return -EINVAL;
 	}
 }
 
-static int mt8173_afe_dais_startup(struct snd_pcm_substream *substream,
-				   struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-	struct snd_pcm_runtime *runtime = substream->runtime;
-	struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
-	int ret;
-
-	memif->substream = substream;
-
-	snd_soc_set_runtime_hwparams(substream, &mt8173_afe_hardware);
-
-	/*
-	 * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be
-	 * smaller than period_size due to AFE's internal buffer.
-	 * This easily leads to overrun when avail_min is period_size.
-	 * One more period can hold the possible unread buffer.
-	 */
-	if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
-		ret = snd_pcm_hw_constraint_minmax(runtime,
-						   SNDRV_PCM_HW_PARAM_PERIODS,
-						   3,
-						   mt8173_afe_hardware.periods_max);
-		if (ret < 0) {
-			dev_err(afe->dev, "hw_constraint_minmax failed\n");
-			return ret;
-		}
-	}
-	ret = snd_pcm_hw_constraint_integer(runtime,
-					    SNDRV_PCM_HW_PARAM_PERIODS);
-	if (ret < 0)
-		dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n");
-	return ret;
-}
-
-static void mt8173_afe_dais_shutdown(struct snd_pcm_substream *substream,
-				     struct snd_soc_dai *dai)
+static int mt8173_memif_fs(struct snd_pcm_substream *substream,
+			   unsigned int rate)
 {
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-	struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
-
-	memif->substream = NULL;
-}
-
-static int mt8173_afe_dais_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 mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-	struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
-	int msb_at_bit33 = 0;
-	int ret;
-
-	dev_dbg(afe->dev,
-		"%s period = %u, rate= %u, channels=%u\n",
-		__func__, params_period_size(params), params_rate(params),
-		params_channels(params));
-
-	ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
-	if (ret < 0)
-		return ret;
+	struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
+	struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
+	int fs;
 
-	msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0;
-	memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr);
-	memif->buffer_size = substream->runtime->dma_bytes;
-
-	/* start */
-	regmap_write(afe->regmap,
-		     memif->data->reg_ofs_base, memif->phys_buf_addr);
-	/* end */
-	regmap_write(afe->regmap,
-		     memif->data->reg_ofs_base + AFE_BASE_END_OFFSET,
-		     memif->phys_buf_addr + memif->buffer_size - 1);
-
-	/* set MSB to 33-bit */
-	regmap_update_bits(afe->regmap, AFE_MEMIF_MSB,
-			   1 << memif->data->msb_shift,
-			   msb_at_bit33 << memif->data->msb_shift);
-
-	/* set channel */
-	if (memif->data->mono_shift >= 0) {
-		unsigned int mono = (params_channels(params) == 1) ? 1 : 0;
-
-		regmap_update_bits(afe->regmap, AFE_DAC_CON1,
-				   1 << memif->data->mono_shift,
-				   mono << memif->data->mono_shift);
-	}
-
-	/* set rate */
-	if (memif->data->fs_shift < 0)
-		return 0;
 	if (memif->data->id == MT8173_AFE_MEMIF_DAI ||
 	    memif->data->id == MT8173_AFE_MEMIF_MOD_DAI) {
-		unsigned int val;
-
-		switch (params_rate(params)) {
+		switch (rate) {
 		case 8000:
-			val = 0;
+			fs = 0;
 			break;
 		case 16000:
-			val = 1;
+			fs = 1;
 			break;
 		case 32000:
-			val = 2;
+			fs = 2;
 			break;
 		default:
 			return -EINVAL;
 		}
-
-		if (memif->data->id == MT8173_AFE_MEMIF_DAI)
-			regmap_update_bits(afe->regmap, AFE_DAC_CON0,
-					   0x3 << memif->data->fs_shift,
-					   val << memif->data->fs_shift);
-		else
-			regmap_update_bits(afe->regmap, AFE_DAC_CON1,
-					   0x3 << memif->data->fs_shift,
-					   val << memif->data->fs_shift);
-
 	} else {
-		int fs = mt8173_afe_i2s_fs(params_rate(params));
-
-		if (fs < 0)
-			return -EINVAL;
-
-		regmap_update_bits(afe->regmap, AFE_DAC_CON1,
-				   0xf << memif->data->fs_shift,
-				   fs << memif->data->fs_shift);
+		fs = mt8173_afe_i2s_fs(rate);
 	}
-
-	return 0;
+	return fs;
 }
 
-static int mt8173_afe_dais_hw_free(struct snd_pcm_substream *substream,
-				   struct snd_soc_dai *dai)
+static int mt8173_irq_fs(struct snd_pcm_substream *substream, unsigned int rate)
 {
-	return snd_pcm_lib_free_pages(substream);
+	return mt8173_afe_i2s_fs(rate);
 }
 
-static int mt8173_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd,
-				   struct snd_soc_dai *dai)
-{
-	struct snd_soc_pcm_runtime *rtd = substream->private_data;
-	struct snd_pcm_runtime * const runtime = substream->runtime;
-	struct mt8173_afe *afe = snd_soc_platform_get_drvdata(rtd->platform);
-	struct mt8173_afe_memif *memif = &afe->memif[rtd->cpu_dai->id];
-	unsigned int counter = runtime->period_size;
-
-	dev_info(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd);
-
-	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
-		if (memif->data->enable_shift >= 0)
-			regmap_update_bits(afe->regmap, AFE_DAC_CON0,
-					   1 << memif->data->enable_shift,
-					   1 << memif->data->enable_shift);
-
-		/* set irq counter */
-		regmap_update_bits(afe->regmap,
-				   memif->data->irq_reg_cnt,
-				   0x3ffff << memif->data->irq_cnt_shift,
-				   counter << memif->data->irq_cnt_shift);
-
-		/* set irq fs */
-		if (memif->data->irq_fs_shift >= 0) {
-			int fs = mt8173_afe_i2s_fs(runtime->rate);
-
-			if (fs < 0)
-				return -EINVAL;
-
-			regmap_update_bits(afe->regmap,
-					   AFE_IRQ_MCU_CON,
-					   0xf << memif->data->irq_fs_shift,
-					   fs << memif->data->irq_fs_shift);
-		}
-		/* enable interrupt */
-		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON,
-				   1 << memif->data->irq_en_shift,
-				   1 << memif->data->irq_en_shift);
-
-		return 0;
-	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
-		if (memif->data->enable_shift >= 0)
-			regmap_update_bits(afe->regmap, AFE_DAC_CON0,
-					   1 << memif->data->enable_shift, 0);
-		/* disable interrupt */
-		regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON,
-				   1 << memif->data->irq_en_shift,
-				   0 << memif->data->irq_en_shift);
-		/* and clear pending IRQ */
-		regmap_write(afe->regmap, AFE_IRQ_CLR,
-			     1 << memif->data->irq_clr_shift);
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-/* FE DAIs */
-static const struct snd_soc_dai_ops mt8173_afe_dai_ops = {
-	.startup	= mt8173_afe_dais_startup,
-	.shutdown	= mt8173_afe_dais_shutdown,
-	.hw_params	= mt8173_afe_dais_hw_params,
-	.hw_free	= mt8173_afe_dais_hw_free,
-	.trigger	= mt8173_afe_dais_trigger,
-};
-
 /* BE DAIs */
 static const struct snd_soc_dai_ops mt8173_afe_i2s_ops = {
 	.startup	= mt8173_afe_i2s_startup,
@@ -761,56 +540,15 @@ static const struct snd_soc_dai_ops mt8173_afe_hdmi_ops = {
 	.shutdown	= mt8173_afe_hdmi_shutdown,
 	.prepare	= mt8173_afe_hdmi_prepare,
 	.trigger	= mt8173_afe_hdmi_trigger,
-
 };
 
-static int mt8173_afe_runtime_suspend(struct device *dev);
-static int mt8173_afe_runtime_resume(struct device *dev);
-
-static int mt8173_afe_dai_suspend(struct snd_soc_dai *dai)
-{
-	struct mt8173_afe *afe = snd_soc_dai_get_drvdata(dai);
-	int i;
-
-	dev_dbg(afe->dev, "%s\n", __func__);
-	if (pm_runtime_status_suspended(afe->dev) || afe->suspended)
-		return 0;
-
-	for (i = 0; i < ARRAY_SIZE(mt8173_afe_backup_list); i++)
-		regmap_read(afe->regmap, mt8173_afe_backup_list[i],
-			    &afe->backup_regs[i]);
-
-	afe->suspended = true;
-	mt8173_afe_runtime_suspend(afe->dev);
-	return 0;
-}
-
-static int mt8173_afe_dai_resume(struct snd_soc_dai *dai)
-{
-	struct mt8173_afe *afe = snd_soc_dai_get_drvdata(dai);
-	int i = 0;
-
-	dev_dbg(afe->dev, "%s\n", __func__);
-	if (pm_runtime_status_suspended(afe->dev) || !afe->suspended)
-		return 0;
-
-	mt8173_afe_runtime_resume(afe->dev);
-
-	for (i = 0; i < ARRAY_SIZE(mt8173_afe_backup_list); i++)
-		regmap_write(afe->regmap, mt8173_afe_backup_list[i],
-			     afe->backup_regs[i]);
-
-	afe->suspended = false;
-	return 0;
-}
-
 static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = {
 	/* FE DAIs: memory intefaces to CPU */
 	{
 		.name = "DL1", /* downlink 1 */
 		.id = MT8173_AFE_MEMIF_DL1,
-		.suspend = mt8173_afe_dai_suspend,
-		.resume = mt8173_afe_dai_resume,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
 		.playback = {
 			.stream_name = "DL1",
 			.channels_min = 1,
@@ -818,12 +556,12 @@ static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = {
 			.rates = SNDRV_PCM_RATE_8000_48000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
-		.ops = &mt8173_afe_dai_ops,
+		.ops = &mtk_afe_fe_ops,
 	}, {
 		.name = "VUL", /* voice uplink */
 		.id = MT8173_AFE_MEMIF_VUL,
-		.suspend = mt8173_afe_dai_suspend,
-		.resume = mt8173_afe_dai_resume,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
 		.capture = {
 			.stream_name = "VUL",
 			.channels_min = 1,
@@ -831,7 +569,7 @@ static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = {
 			.rates = SNDRV_PCM_RATE_8000_48000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
-		.ops = &mt8173_afe_dai_ops,
+		.ops = &mtk_afe_fe_ops,
 	}, {
 	/* BE DAIs */
 		.name = "I2S",
@@ -860,8 +598,8 @@ static struct snd_soc_dai_driver mt8173_afe_hdmi_dais[] = {
 	{
 		.name = "HDMI",
 		.id = MT8173_AFE_MEMIF_HDMI,
-		.suspend = mt8173_afe_dai_suspend,
-		.resume = mt8173_afe_dai_resume,
+		.suspend = mtk_afe_dai_suspend,
+		.resume = mtk_afe_dai_resume,
 		.playback = {
 			.stream_name = "HDMI",
 			.channels_min = 2,
@@ -872,7 +610,7 @@ static struct snd_soc_dai_driver mt8173_afe_hdmi_dais[] = {
 				SNDRV_PCM_RATE_192000,
 			.formats = SNDRV_PCM_FMTBIT_S16_LE,
 		},
-		.ops = &mt8173_afe_dai_ops,
+		.ops = &mtk_afe_fe_ops,
 	}, {
 	/* BE DAIs */
 		.name = "HDMIO",
@@ -978,105 +716,222 @@ static const char *aud_clks[MT8173_CLK_NUM] = {
 	[MT8173_CLK_BCK1] =  "bck1",
 };
 
-static const struct mt8173_afe_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
+static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = {
 	{
 		.name = "DL1",
 		.id = MT8173_AFE_MEMIF_DL1,
 		.reg_ofs_base = AFE_DL1_BASE,
 		.reg_ofs_cur = AFE_DL1_CUR,
+		.fs_reg = AFE_DAC_CON1,
 		.fs_shift = 0,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
 		.mono_shift = 21,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
 		.enable_shift = 1,
-		.irq_reg_cnt = AFE_IRQ_CNT1,
-		.irq_cnt_shift = 0,
-		.irq_en_shift = 0,
-		.irq_fs_shift = 4,
-		.irq_clr_shift = 0,
+		.msb_reg = AFE_MEMIF_MSB,
 		.msb_shift = 0,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
 	}, {
 		.name = "DL2",
 		.id = MT8173_AFE_MEMIF_DL2,
 		.reg_ofs_base = AFE_DL2_BASE,
 		.reg_ofs_cur = AFE_DL2_CUR,
+		.fs_reg = AFE_DAC_CON1,
 		.fs_shift = 4,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
 		.mono_shift = 22,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
 		.enable_shift = 2,
-		.irq_reg_cnt = AFE_IRQ_CNT1,
-		.irq_cnt_shift = 20,
-		.irq_en_shift = 2,
-		.irq_fs_shift = 16,
-		.irq_clr_shift = 2,
+		.msb_reg = AFE_MEMIF_MSB,
 		.msb_shift = 1,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
 	}, {
 		.name = "VUL",
 		.id = MT8173_AFE_MEMIF_VUL,
 		.reg_ofs_base = AFE_VUL_BASE,
 		.reg_ofs_cur = AFE_VUL_CUR,
+		.fs_reg = AFE_DAC_CON1,
 		.fs_shift = 16,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
 		.mono_shift = 27,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
 		.enable_shift = 3,
-		.irq_reg_cnt = AFE_IRQ_CNT2,
-		.irq_cnt_shift = 0,
-		.irq_en_shift = 1,
-		.irq_fs_shift = 8,
-		.irq_clr_shift = 1,
+		.msb_reg = AFE_MEMIF_MSB,
 		.msb_shift = 6,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
 	}, {
 		.name = "DAI",
 		.id = MT8173_AFE_MEMIF_DAI,
 		.reg_ofs_base = AFE_DAI_BASE,
 		.reg_ofs_cur = AFE_DAI_CUR,
+		.fs_reg = AFE_DAC_CON0,
 		.fs_shift = 24,
+		.fs_maskbit = 0x3,
+		.mono_reg = -1,
 		.mono_shift = -1,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
 		.enable_shift = 4,
-		.irq_reg_cnt = AFE_IRQ_CNT2,
-		.irq_cnt_shift = 20,
-		.irq_en_shift = 3,
-		.irq_fs_shift = 20,
-		.irq_clr_shift = 3,
+		.msb_reg = AFE_MEMIF_MSB,
 		.msb_shift = 5,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
 	}, {
 		.name = "AWB",
 		.id = MT8173_AFE_MEMIF_AWB,
 		.reg_ofs_base = AFE_AWB_BASE,
 		.reg_ofs_cur = AFE_AWB_CUR,
+		.fs_reg = AFE_DAC_CON1,
 		.fs_shift = 12,
+		.fs_maskbit = 0xf,
+		.mono_reg = AFE_DAC_CON1,
 		.mono_shift = 24,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
 		.enable_shift = 6,
-		.irq_reg_cnt = AFE_IRQ_CNT7,
-		.irq_cnt_shift = 0,
-		.irq_en_shift = 14,
-		.irq_fs_shift = 24,
-		.irq_clr_shift = 6,
+		.msb_reg = AFE_MEMIF_MSB,
 		.msb_shift = 3,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
 	}, {
 		.name = "MOD_DAI",
 		.id = MT8173_AFE_MEMIF_MOD_DAI,
 		.reg_ofs_base = AFE_MOD_PCM_BASE,
 		.reg_ofs_cur = AFE_MOD_PCM_CUR,
+		.fs_reg = AFE_DAC_CON1,
 		.fs_shift = 30,
+		.fs_maskbit = 0x3,
+		.mono_reg = AFE_DAC_CON1,
 		.mono_shift = 30,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = AFE_DAC_CON0,
 		.enable_shift = 7,
-		.irq_reg_cnt = AFE_IRQ_CNT2,
-		.irq_cnt_shift = 20,
-		.irq_en_shift = 3,
-		.irq_fs_shift = 20,
-		.irq_clr_shift = 3,
+		.msb_reg = AFE_MEMIF_MSB,
 		.msb_shift = 4,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
 	}, {
 		.name = "HDMI",
 		.id = MT8173_AFE_MEMIF_HDMI,
 		.reg_ofs_base = AFE_HDMI_OUT_BASE,
 		.reg_ofs_cur = AFE_HDMI_OUT_CUR,
+		.fs_reg = -1,
 		.fs_shift = -1,
+		.fs_maskbit = -1,
+		.mono_reg = -1,
 		.mono_shift = -1,
+		.hd_reg = -1,
+		.hd_shift = -1,
+		.enable_reg = -1,
 		.enable_shift = -1,
-		.irq_reg_cnt = AFE_IRQ_CNT5,
+		.msb_reg = AFE_MEMIF_MSB,
+		.msb_shift = 8,
+		.agent_disable_reg = -1,
+		.agent_disable_shift = -1,
+	},
+};
+
+static const struct mtk_base_irq_data irq_data[MT8173_AFE_IRQ_NUM] = {
+	{
+		.id = MT8173_AFE_IRQ_DL1,
+		.irq_cnt_reg = AFE_IRQ_CNT1,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 0,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 4,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_CLR,
+		.irq_clr_shift = 0,
+	}, {
+		.id = MT8173_AFE_IRQ_DL2,
+		.irq_cnt_reg = AFE_IRQ_CNT1,
+		.irq_cnt_shift = 20,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 2,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 16,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_CLR,
+		.irq_clr_shift = 2,
+
+	}, {
+		.id = MT8173_AFE_IRQ_VUL,
+		.irq_cnt_reg = AFE_IRQ_CNT2,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 1,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 8,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_CLR,
+		.irq_clr_shift = 1,
+	}, {
+		.id = MT8173_AFE_IRQ_DAI,
+		.irq_cnt_reg = AFE_IRQ_CNT2,
+		.irq_cnt_shift = 20,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 3,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 20,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_CLR,
+		.irq_clr_shift = 3,
+	}, {
+		.id = MT8173_AFE_IRQ_AWB,
+		.irq_cnt_reg = AFE_IRQ_CNT7,
 		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 14,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 24,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_CLR,
+		.irq_clr_shift = 6,
+	}, {
+		.id = MT8173_AFE_IRQ_DAI,
+		.irq_cnt_reg = AFE_IRQ_CNT2,
+		.irq_cnt_shift = 20,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
+		.irq_en_shift = 3,
+		.irq_fs_reg = AFE_IRQ_MCU_CON,
+		.irq_fs_shift = 20,
+		.irq_fs_maskbit = 0xf,
+		.irq_clr_reg = AFE_IRQ_CLR,
+		.irq_clr_shift = 3,
+	}, {
+		.id = MT8173_AFE_IRQ_HDMI,
+		.irq_cnt_reg = AFE_IRQ_CNT5,
+		.irq_cnt_shift = 0,
+		.irq_cnt_maskbit = 0x3ffff,
+		.irq_en_reg = AFE_IRQ_MCU_CON,
 		.irq_en_shift = 12,
+		.irq_fs_reg = -1,
 		.irq_fs_shift = -1,
+		.irq_fs_maskbit = -1,
+		.irq_clr_reg = AFE_IRQ_CLR,
 		.irq_clr_shift = 4,
-		.msb_shift = 8,
 	},
 };
 
@@ -1090,7 +945,7 @@ static const struct regmap_config mt8173_afe_regmap_config = {
 
 static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id)
 {
-	struct mt8173_afe *afe = dev_id;
+	struct mtk_base_afe *afe = dev_id;
 	unsigned int reg_value;
 	int i, ret;
 
@@ -1102,9 +957,15 @@ static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id)
 	}
 
 	for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++) {
-		struct mt8173_afe_memif *memif = &afe->memif[i];
+		struct mtk_base_afe_memif *memif = &afe->memif[i];
+		struct mtk_base_afe_irq *irq;
 
-		if (!(reg_value & (1 << memif->data->irq_clr_shift)))
+		if (memif->irq_usage < 0)
+			continue;
+
+		irq = &afe->irqs[memif->irq_usage];
+
+		if (!(reg_value & (1 << irq->irq_data->irq_clr_shift)))
 			continue;
 
 		snd_pcm_period_elapsed(memif->substream);
@@ -1112,14 +973,16 @@ static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id)
 
 err_irq:
 	/* clear irq */
-	regmap_write(afe->regmap, AFE_IRQ_CLR, reg_value & AFE_IRQ_STATUS_BITS);
+	regmap_write(afe->regmap, AFE_IRQ_CLR,
+		     reg_value & AFE_IRQ_STATUS_BITS);
 
 	return IRQ_HANDLED;
 }
 
 static int mt8173_afe_runtime_suspend(struct device *dev)
 {
-	struct mt8173_afe *afe = dev_get_drvdata(dev);
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	/* disable AFE */
 	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0);
@@ -1127,44 +990,46 @@ static int mt8173_afe_runtime_suspend(struct device *dev)
 	/* disable AFE clk */
 	regmap_update_bits(afe->regmap, AUDIO_TOP_CON0,
 			   AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_I2S1_M]);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_I2S2_M]);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_BCK0]);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_BCK1]);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD]);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_INFRASYS_AUD]);
+
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK1]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]);
 	return 0;
 }
 
 static int mt8173_afe_runtime_resume(struct device *dev)
 {
-	struct mt8173_afe *afe = dev_get_drvdata(dev);
+	struct mtk_base_afe *afe = dev_get_drvdata(dev);
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 	int ret;
 
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_INFRASYS_AUD]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]);
 	if (ret)
 		return ret;
 
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
 	if (ret)
 		goto err_infra;
 
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_TOP_PDN_AUD]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]);
 	if (ret)
 		goto err_top_aud_bus;
 
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_BCK0]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_BCK0]);
 	if (ret)
 		goto err_top_aud;
 
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_BCK1]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_BCK1]);
 	if (ret)
 		goto err_bck0;
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_I2S1_M]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S1_M]);
 	if (ret)
 		goto err_i2s1_m;
-	ret = clk_prepare_enable(afe->clocks[MT8173_CLK_I2S2_M]);
+	ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S2_M]);
 	if (ret)
 		goto err_i2s2_m;
 
@@ -1181,35 +1046,37 @@ static int mt8173_afe_runtime_resume(struct device *dev)
 	/* enable AFE */
 	regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1);
 	return 0;
+
 err_i2s1_m:
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_I2S1_M]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]);
 err_i2s2_m:
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_I2S2_M]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]);
 err_bck0:
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_BCK0]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]);
 err_top_aud:
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]);
 err_top_aud_bus:
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]);
 err_infra:
-	clk_disable_unprepare(afe->clocks[MT8173_CLK_INFRASYS_AUD]);
+	clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]);
 	return ret;
 }
 
-static int mt8173_afe_init_audio_clk(struct mt8173_afe *afe)
+static int mt8173_afe_init_audio_clk(struct mtk_base_afe *afe)
 {
 	size_t i;
+	struct mt8173_afe_private *afe_priv = afe->platform_priv;
 
 	for (i = 0; i < ARRAY_SIZE(aud_clks); i++) {
-		afe->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
-		if (IS_ERR(afe->clocks[i])) {
+		afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]);
+		if (IS_ERR(afe_priv->clocks[i])) {
 			dev_err(afe->dev, "%s devm_clk_get %s fail\n",
 				__func__, aud_clks[i]);
-			return PTR_ERR(afe->clocks[i]);
+			return PTR_ERR(afe_priv->clocks[i]);
 		}
 	}
-	clk_set_rate(afe->clocks[MT8173_CLK_BCK0], 22579200); /* 22M */
-	clk_set_rate(afe->clocks[MT8173_CLK_BCK1], 24576000); /* 24M */
+	clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK0], 22579200); /* 22M */
+	clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK1], 24576000); /* 24M */
 	return 0;
 }
 
@@ -1217,7 +1084,8 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 {
 	int ret, i;
 	unsigned int irq_id;
-	struct mt8173_afe *afe;
+	struct mtk_base_afe *afe;
+	struct mt8173_afe_private *afe_priv;
 	struct resource *res;
 
 	ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33));
@@ -1228,6 +1096,12 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 	if (!afe)
 		return -ENOMEM;
 
+	afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv),
+					  GFP_KERNEL);
+	afe_priv = afe->platform_priv;
+	if (!afe_priv)
+		return -ENOMEM;
+
 	afe->dev = &pdev->dev;
 
 	irq_id = platform_get_irq(pdev, 0);
@@ -1259,8 +1133,30 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++)
+	/* memif % irq initialize*/
+	afe->memif_size = MT8173_AFE_MEMIF_NUM;
+	afe->memif = devm_kcalloc(afe->dev, afe->memif_size,
+				  sizeof(*afe->memif), GFP_KERNEL);
+	if (!afe->memif)
+		return -ENOMEM;
+
+	afe->irqs_size = MT8173_AFE_IRQ_NUM;
+	afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size,
+				 sizeof(*afe->irqs), GFP_KERNEL);
+	if (!afe->irqs)
+		return -ENOMEM;
+
+	for (i = 0; i < afe->irqs_size; i++) {
 		afe->memif[i].data = &memif_data[i];
+		afe->irqs[i].irq_data = &irq_data[i];
+		afe->irqs[i].irq_occupyed = true;
+		afe->memif[i].irq_usage = i;
+		afe->memif[i].const_irq = 1;
+	}
+
+	afe->mtk_afe_hardware = &mt8173_afe_hardware;
+	afe->memif_fs = mt8173_memif_fs;
+	afe->irq_fs = mt8173_irq_fs;
 
 	platform_set_drvdata(pdev, afe);
 
@@ -1271,7 +1167,12 @@ static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev)
 			goto err_pm_disable;
 	}
 
-	ret = snd_soc_register_platform(&pdev->dev, &mt8173_afe_pcm_platform);
+	afe->reg_back_up_list = mt8173_afe_backup_list;
+	afe->reg_back_up_list_num = ARRAY_SIZE(mt8173_afe_backup_list);
+	afe->runtime_resume = mt8173_afe_runtime_resume;
+	afe->runtime_suspend = mt8173_afe_runtime_suspend;
+
+	ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform);
 	if (ret)
 		goto err_pm_disable;
 
-- 
1.9.1

[toc] | [prev] | [next] | [standalone]


#1424762 — [alsa-devel] [PATCH v5 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option.

FromGarlic Tseng <garlic.tseng@mediatek.com>
Date2016-06-17 09:50 +0200
Subject[alsa-devel] [PATCH v5 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option.
Message-ID<rKWHo-3Cb-49@gated-at.bofh.it>
In reply to#1424755
Add machine driver and config option for MT2701.

Signed-off-by: Garlic Tseng <garlic.tseng@mediatek.com>
---
 sound/soc/mediatek/Kconfig                 |  21 ++
 sound/soc/mediatek/Makefile                |   1 +
 sound/soc/mediatek/mt2701/Makefile         |  19 ++
 sound/soc/mediatek/mt2701/mt2701-cs42448.c | 422 +++++++++++++++++++++++++++++
 4 files changed, 463 insertions(+)
 create mode 100644 sound/soc/mediatek/mt2701/Makefile
 create mode 100644 sound/soc/mediatek/mt2701/mt2701-cs42448.c

diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig
index 705904b..2fbe543 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -1,6 +1,27 @@
 config SND_SOC_MEDIATEK
 	tristate
 
+config SND_SOC_MT2701
+	tristate "ASoC support for Mediatek MT2701 chip"
+	depends on ARCH_MEDIATEK
+	select SND_SOC_MEDIATEK
+	help
+	  This adds ASoC driver for Mediatek MT2701 boards
+	  that can be used with other codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
+config SND_SOC_MT2701_CS42448
+	tristate "ASoc Audio driver for MT2701 with CS42448 codec"
+	depends on SND_SOC_MT2701
+	select SND_SOC_CS42XX8_I2C
+	select SND_SOC_BT_SCO
+	help
+	  This adds ASoC driver for Mediatek MT2701 boards
+	  with the CS42448 codecs.
+	  Select Y if you have such device.
+	  If unsure select "N".
+
 config SND_SOC_MT8173
 	tristate "ASoC support for Mediatek MT8173 chip"
 	depends on ARCH_MEDIATEK
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile
index 4fe8068..6bcab35 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_SND_SOC_MEDIATEK) += common/
+obj-$(CONFIG_SND_SOC_MT2701) += mt2701/
 obj-$(CONFIG_SND_SOC_MT8173) += mt8173/
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile
new file mode 100644
index 0000000..31c3d04
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/Makefile
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2015 MediaTek Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# 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.
+#
+
+# platform driver
+snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o
+obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o
+
+# machine driver
+obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
new file mode 100644
index 0000000..0e48cb9
--- /dev/null
+++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c
@@ -0,0 +1,422 @@
+/*
+ * mt2701-cs42448.c  --  MT2701 CS42448 ALSA SoC machine driver
+ *
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ir Lian <ir.lian@mediatek.com>
+ *              Garlic Tseng <garlic.tseng@mediatek.com>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <sound/soc.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/of_gpio.h>
+
+#include "mt2701-afe-common.h"
+
+struct mt2701_cs42448_private {
+	int i2s1_in_mux;
+	int i2s1_in_mux_gpio_sel_1;
+	int i2s1_in_mux_gpio_sel_2;
+};
+
+static const char * const i2sin_mux_switch_text[] = {
+	"ADC_SDOUT2",
+	"ADC_SDOUT3",
+	"I2S_IN_1",
+	"I2S_IN_2",
+};
+
+static const struct soc_enum i2sin_mux_enum =
+	SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text);
+
+static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+	ucontrol->value.integer.value[0] = priv->i2s1_in_mux;
+	return 0;
+}
+
+static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+	struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card);
+
+	if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux)
+		return 0;
+
+	switch (ucontrol->value.integer.value[0]) {
+	case 0:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+		break;
+	case 1:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0);
+		break;
+	case 2:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+		break;
+	case 3:
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1);
+		gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1);
+		break;
+	default:
+		dev_warn(card->dev, "%s invalid setting\n", __func__);
+	}
+
+	priv->i2s1_in_mux = ucontrol->value.integer.value[0];
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget
+			mt2701_cs42448_asoc_card_dapm_widgets[] = {
+	SND_SOC_DAPM_LINE("Line Out Jack", NULL),
+	SND_SOC_DAPM_MIC("AMIC", NULL),
+	SND_SOC_DAPM_LINE("Tuner In", NULL),
+	SND_SOC_DAPM_LINE("Satellite Tuner In", NULL),
+	SND_SOC_DAPM_LINE("AUX In", NULL),
+};
+
+static const struct snd_kcontrol_new mt2701_cs42448_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Line Out Jack"),
+	SOC_DAPM_PIN_SWITCH("AMIC"),
+	SOC_DAPM_PIN_SWITCH("Tuner In"),
+	SOC_DAPM_PIN_SWITCH("Satellite Tuner In"),
+	SOC_DAPM_PIN_SWITCH("AUX In"),
+	SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum,
+		     mt2701_cs42448_i2sin1_mux_get,
+		     mt2701_cs42448_i2sin1_mux_set),
+};
+
+static const unsigned int mt2701_cs42448_sampling_rates[] = {48000};
+
+static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = {
+		.count = ARRAY_SIZE(mt2701_cs42448_sampling_rates),
+		.list = mt2701_cs42448_sampling_rates,
+		.mask = 0,
+};
+
+static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream)
+{
+	int err;
+
+	err = snd_pcm_hw_constraint_list(substream->runtime, 0,
+					 SNDRV_PCM_HW_PARAM_RATE,
+					 &mt2701_cs42448_constraints_rates);
+	if (err < 0) {
+		dev_err(substream->pcm->card->dev,
+			"%s snd_pcm_hw_constraint_list failed: 0x%x\n",
+			__func__, err);
+		return err;
+	}
+	return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = {
+	.startup = mt2701_cs42448_fe_ops_startup,
+};
+
+static int mt2701_cs42448_be_ops_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;
+	/* codec slave, mt2701 master */
+	unsigned int fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			    | SND_SOC_DAIFMT_CONT;
+	unsigned int mclk_rate;
+	unsigned int rate = params_rate(params);
+	unsigned int div_mclk_to_bck = rate > 192000 ? 2 : 4;
+	unsigned int div_bck_to_lrck = 64;
+
+	mclk_rate = rate * div_bck_to_lrck * div_mclk_to_bck;
+
+	/* mt2701 mclk */
+	snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT);
+	/* mt2701 bck */
+	snd_soc_dai_set_clkdiv(cpu_dai, DIV_ID_MCLK_TO_BCK, div_mclk_to_bck);
+	/* mt2701 lrck */
+	snd_soc_dai_set_clkdiv(cpu_dai, DIV_ID_BCK_TO_LRCK, div_bck_to_lrck);
+	/* mt2701 master */
+	snd_soc_dai_set_fmt(cpu_dai, fmt);
+
+	/* codec mclk */
+	snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN);
+	/* codec slave */
+	snd_soc_dai_set_fmt(codec_dai, fmt);
+	return 0;
+}
+
+static struct snd_soc_ops mt2701_cs42448_be_ops = {
+	.hw_params = mt2701_cs42448_be_ops_hw_params
+};
+
+enum {
+	DAI_LINK_FE_MULTI_CH_OUT,
+	DAI_LINK_FE_PCM0_IN,
+	DAI_LINK_FE_PCM1_IN,
+	DAI_LINK_FE_BT_OUT,
+	DAI_LINK_FE_BT_IN,
+	DAI_LINK_BE_I2S0,
+	DAI_LINK_BE_I2S1,
+	DAI_LINK_BE_I2S2,
+	DAI_LINK_BE_I2S3,
+	DAI_LINK_BE_MRG_BT,
+};
+
+static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = {
+	/* FE */
+	[DAI_LINK_FE_MULTI_CH_OUT] = {
+		.name = "mt2701-cs42448-multi-ch-out",
+		.stream_name = "mt2701-cs42448-multi-ch-out",
+		.cpu_dai_name = "PCM_multi",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	[DAI_LINK_FE_PCM0_IN] = {
+		.name = "mt2701-cs42448-pcm0",
+		.stream_name = "mt2701-cs42448-pcm0-data-UL",
+		.cpu_dai_name = "PCM0",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_FE_PCM1_IN] = {
+		.name = "mt2701-cs42448-pcm1-data-UL",
+		.stream_name = "mt2701-cs42448-pcm1-data-UL",
+		.cpu_dai_name = "PCM1",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.ops = &mt2701_cs42448_48k_fe_ops,
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_FE_BT_OUT] = {
+		.name = "mt2701-cs42448-pcm-BT-out",
+		.stream_name = "mt2701-cs42448-pcm-BT",
+		.cpu_dai_name = "PCM_BT_DL",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_playback = 1,
+	},
+	[DAI_LINK_FE_BT_IN] = {
+		.name = "mt2701-cs42448-pcm-BT-in",
+		.stream_name = "mt2701-cs42448-pcm-BT",
+		.cpu_dai_name = "PCM_BT_UL",
+		.codec_name = "snd-soc-dummy",
+		.codec_dai_name = "snd-soc-dummy-dai",
+		.trigger = {SND_SOC_DPCM_TRIGGER_POST,
+			    SND_SOC_DPCM_TRIGGER_POST},
+		.dynamic = 1,
+		.dpcm_capture = 1,
+	},
+	/* BE */
+	[DAI_LINK_BE_I2S0] = {
+		.name = "mt2701-cs42448-I2S0",
+		.cpu_dai_name = "I2S0",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S1] = {
+		.name = "mt2701-cs42448-I2S1",
+		.cpu_dai_name = "I2S1",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S2] = {
+		.name = "mt2701-cs42448-I2S2",
+		.cpu_dai_name = "I2S2",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_I2S3] = {
+		.name = "mt2701-cs42448-I2S3",
+		.cpu_dai_name = "I2S3",
+		.no_pcm = 1,
+		.codec_dai_name = "cs42448",
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS
+			 | SND_SOC_DAIFMT_GATED,
+		.ops = &mt2701_cs42448_be_ops,
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+	[DAI_LINK_BE_MRG_BT] = {
+		.name = "mt2701-cs42448-MRG-BT",
+		.cpu_dai_name = "MRG BT",
+		.no_pcm = 1,
+		.codec_dai_name = "bt-sco-pcm",
+		.dpcm_playback = 1,
+		.dpcm_capture = 1,
+	},
+};
+
+static struct snd_soc_card mt2701_cs42448_soc_card = {
+	.name = "mt2701-cs42448",
+	.owner = THIS_MODULE,
+	.dai_link = mt2701_cs42448_dai_links,
+	.num_links = ARRAY_SIZE(mt2701_cs42448_dai_links),
+	.controls = mt2701_cs42448_controls,
+	.num_controls = ARRAY_SIZE(mt2701_cs42448_controls),
+	.dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets),
+};
+
+static int mt2701_cs42448_machine_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &mt2701_cs42448_soc_card;
+	int ret;
+	int i;
+	struct device_node *platform_node, *codec_node, *codec_node_bt_mrg;
+	struct mt2701_cs42448_private *priv =
+		devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private),
+			     GFP_KERNEL);
+	struct device *dev = &pdev->dev;
+
+	if (!priv)
+		return -ENOMEM;
+
+	platform_node = of_parse_phandle(pdev->dev.of_node,
+					 "mediatek,platform", 0);
+	if (!platform_node) {
+		dev_err(&pdev->dev, "Property 'platform' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt2701_cs42448_dai_links[i].platform_name)
+			continue;
+		mt2701_cs42448_dai_links[i].platform_of_node = platform_node;
+	}
+
+	card->dev = dev;
+
+	codec_node = of_parse_phandle(pdev->dev.of_node,
+				      "mediatek,audio-codec", 0);
+	if (!codec_node) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec' missing or invalid\n");
+		return -EINVAL;
+	}
+	for (i = 0; i < card->num_links; i++) {
+		if (mt2701_cs42448_dai_links[i].codec_name)
+			continue;
+		mt2701_cs42448_dai_links[i].codec_of_node = codec_node;
+	}
+
+	codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node,
+					     "mediatek,audio-codec-bt-mrg", 0);
+	if (!codec_node_bt_mrg) {
+		dev_err(&pdev->dev,
+			"Property 'audio-codec-bt-mrg' missing or invalid\n");
+		return -EINVAL;
+	}
+	mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codec_of_node
+							= codec_node_bt_mrg;
+
+	ret = snd_soc_of_parse_audio_routing(card, "audio-routing");
+	if (ret) {
+		dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret);
+		return ret;
+	}
+
+	priv->i2s1_in_mux_gpio_sel_1 =
+		of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0);
+	if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) {
+		ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1,
+					"i2s1_in_mux_gpio_sel_1");
+		if (ret)
+			dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n",
+				 __func__, ret);
+		gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0);
+	}
+
+	priv->i2s1_in_mux_gpio_sel_2 =
+		of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0);
+	if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) {
+		ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2,
+					"i2s1_in_mux_gpio_sel_2");
+		if (ret)
+			dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n",
+				 __func__, ret);
+		gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0);
+	}
+	snd_soc_card_set_drvdata(card, priv);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mt2701_cs42448_machine_dt_match[] = {
+	{.compatible = "mediatek,mt2701-cs42448-machine",},
+	{}
+};
+#endif
+
+static struct platform_driver mt2701_cs42448_machine = {
+	.driver = {
+		.name = "mt2701-cs42448",
+		   #ifdef CONFIG_OF
+		   .of_match_table = mt2701_cs42448_machine_dt_match,
+		   #endif
+	},
+	.probe = mt2701_cs42448_machine_probe,
+};
+
+module_platform_driver(mt2701_cs42448_machine);
+
+/* Module information */
+MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver");
+MODULE_AUTHOR("Ir Lian <ir.lian@mediatek.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("mt2701 cs42448 soc card");
-- 
1.9.1

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web