All of lore.kernel.org
 help / color / mirror / Atom feed
From: Garlic Tseng <garlic.tseng@mediatek.com>
To: <broonie@kernel.org>, <tiwai@suse.de>
Cc: <garlic.tseng@mediatek.com>, <srv_heupstream@mediatek.com>,
	<linux-mediatek@lists.infradead.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>, <alsa-devel@alsa-project.org>,
	<koro.chen@mediatek.com>, <PC.Liao@mediatek.com>,
	<ir.lian@mediatek.com>
Subject: [alsa-devel] [PATCH v2 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option.
Date: Fri, 3 Jun 2016 12:56:24 +0800	[thread overview]
Message-ID: <1464929784-5489-10-git-send-email-garlic.tseng@mediatek.com> (raw)
In-Reply-To: <1464929784-5489-1-git-send-email-garlic.tseng@mediatek.com>

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 ff1a419..0ecb785 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -7,6 +7,27 @@ config SND_SOC_MEDIATEK
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+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 "SND_SOC_MT2701_CS42448"
+	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 3d893be..5133215 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
 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..fce159f
--- /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, /*better way to get device?*/
+			"%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

WARNING: multiple messages have this Message-ID (diff)
From: Garlic Tseng <garlic.tseng@mediatek.com>
To: broonie@kernel.org, tiwai@suse.de
Cc: garlic.tseng@mediatek.com, srv_heupstream@mediatek.com,
	linux-mediatek@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, alsa-devel@alsa-project.org,
	koro.chen@mediatek.com, PC.Liao@mediatek.com,
	ir.lian@mediatek.com
Subject: [alsa-devel] [PATCH v2 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option.
Date: Fri, 3 Jun 2016 12:56:24 +0800	[thread overview]
Message-ID: <1464929784-5489-10-git-send-email-garlic.tseng@mediatek.com> (raw)
In-Reply-To: <1464929784-5489-1-git-send-email-garlic.tseng@mediatek.com>

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 ff1a419..0ecb785 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -7,6 +7,27 @@ config SND_SOC_MEDIATEK
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+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 "SND_SOC_MT2701_CS42448"
+	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 3d893be..5133215 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
 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..fce159f
--- /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, /*better way to get device?*/
+			"%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

WARNING: multiple messages have this Message-ID (diff)
From: garlic.tseng@mediatek.com (Garlic Tseng)
To: linux-arm-kernel@lists.infradead.org
Subject: [alsa-devel] [PATCH v2 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option.
Date: Fri, 3 Jun 2016 12:56:24 +0800	[thread overview]
Message-ID: <1464929784-5489-10-git-send-email-garlic.tseng@mediatek.com> (raw)
In-Reply-To: <1464929784-5489-1-git-send-email-garlic.tseng@mediatek.com>

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 ff1a419..0ecb785 100644
--- a/sound/soc/mediatek/Kconfig
+++ b/sound/soc/mediatek/Kconfig
@@ -7,6 +7,27 @@ config SND_SOC_MEDIATEK
 	  Select Y if you have such device.
 	  If unsure select "N".
 
+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 "SND_SOC_MT2701_CS42448"
+	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 3d893be..5133215 100644
--- a/sound/soc/mediatek/Makefile
+++ b/sound/soc/mediatek/Makefile
@@ -1,3 +1,4 @@
 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..fce159f
--- /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, /*better way to get device?*/
+			"%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

  parent reply	other threads:[~2016-06-03  4:56 UTC|newest]

Thread overview: 54+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-03  4:56 [alsa-devel] [PATCH v2 0/9] ASoC: Mediatek: Add support for MT2701 SOC Garlic Tseng
2016-06-03  4:56 ` Garlic Tseng
2016-06-03  4:56 ` Garlic Tseng
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 1/9] ASoC: mediatek: Refine mt8173 driver and change config option Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 2/9] ASoC: mediatek: implement mediatek common structure Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-07 15:54   ` Mark Brown
2016-06-07 15:54     ` Mark Brown
2016-06-07 15:54     ` Mark Brown
2016-06-08  2:06     ` [alsa-devel] " Garlic Tseng
2016-06-08  2:06       ` Garlic Tseng
2016-06-08  2:06       ` Garlic Tseng
2016-06-09 10:44       ` Mark Brown
2016-06-09 10:44         ` Mark Brown
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 3/9] ASoC: mediatek: let mt8173 use " Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 4/9] ASoC: mediatek: add documents for mt2701 Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-29 19:16   ` Applied "ASoC: mediatek: add documents for mt2701" to the asoc tree Mark Brown
2016-06-29 19:16     ` Mark Brown
2016-06-29 19:16     ` Mark Brown
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 5/9] ASoC: mediatek: add structure define and clock control for 2701 Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-07 16:15   ` Mark Brown
2016-06-07 16:15     ` Mark Brown
2016-06-08  1:44     ` Garlic Tseng
2016-06-08  1:44       ` Garlic Tseng
2016-06-08  1:44       ` Garlic Tseng
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 6/9] ASoC: mediatek: add mt2701 platform driver implementation Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-07 16:31   ` Mark Brown
2016-06-07 16:31     ` Mark Brown
2016-06-07 16:31     ` Mark Brown
2016-06-08  3:32     ` Garlic Tseng
2016-06-08  3:32       ` Garlic Tseng
2016-06-08  3:32       ` Garlic Tseng
2016-06-09 10:44       ` Mark Brown
2016-06-09 10:44         ` Mark Brown
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 7/9] ASoC: bt-sco: extend rate and add a general compatible string Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56 ` [alsa-devel] [PATCH v2 8/9] ASoC: mediatek: add BT implementation Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng
2016-06-03  4:56 ` Garlic Tseng [this message]
2016-06-03  4:56   ` [alsa-devel] [PATCH v2 9/9] ASoC: mediatek: Add mt2701-cs42448 driver and config option Garlic Tseng
2016-06-03  4:56   ` Garlic Tseng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1464929784-5489-10-git-send-email-garlic.tseng@mediatek.com \
    --to=garlic.tseng@mediatek.com \
    --cc=PC.Liao@mediatek.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    --cc=ir.lian@mediatek.com \
    --cc=koro.chen@mediatek.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mediatek@lists.infradead.org \
    --cc=srv_heupstream@mediatek.com \
    --cc=tiwai@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.