linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
@ 2015-04-30 17:15 Srinivas Kandagatla
  2015-04-30 17:16 ` [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check Srinivas Kandagatla
                   ` (16 more replies)
  0 siblings, 17 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:15 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

Hi All,

This patchset adds apq8016 audio support into lpass driver. Existing Lpass
driver can not be used as-it-is for apq8016 as it contains code specific to
ipq806x. Also the driver only supports single i2s port, single dma channel and
single bitclk control.

APQ8016 has 4 MI2S( Primary, Secondary, Tertiary, Quaternary) which can be routed
to internal wcd codec or external codecs. This routing is controlled by 2 mux
registers.

This patch series firstly re-organizes the lpass driver such that the SOC
specific bits are moved away from the driver. And secondly the SOC specifics
are now passed as lpass variant data which would include various register
offsets, dma channel allocations and SOC specific clock handling.

Finally the patchset add apq8016 lpass and machine driver.

This patchset also has two trivial cleanup patches which are to do with
redundant checks and removing unnecessary header files.

All these patches are tested for HDMI audio via adv7533 bridge and Analog audio
on APQ8016-SBC and msm8916-mtp boards. I dont have access to ipq806x boards to
test these patches.

This is very first version of the patches which was developed with very
mimimal/no access to IP documentation. I would like to get your opinon on the
over all approch.


Kenneth/Patrick,
	Could you please try these patches on storm board?

Thanks,
srini


Srinivas Kandagatla (14):
  ASoC: qcom: Remove redundant error check.
  ASoC: qcom: remove unnecessary header files
  ASoC: qcom: move ipq806x specific bits out of lpass driver.
  ASoC: qcom: remove hardcoded i2s port number
  ASoC: qcom: remove hardcoded dma channel
  ASoC: qcom: support bitclk and osrclk per i2s port
  ASoC: qcom: add no osr clk flag to lpass variant
  ASoC: qcom: add dma channel control offset to variant data
  ASoC: qcom: Add ability to handle interrupts per dma channel
  ASoC: qcom: add bit map to track static dma channel allocations
  ASoC: qcom: Add apq8016 lpass driver support
  ASoC: qcom: add apq8016 sound card support
  ASoC: qcom: Document apq8016 bindings.
  ASoC: qcom: document apq8016 machine driver bindings

 .../bindings/sound/qcom,apq8016-machine.txt        |  61 ++++++
 .../devicetree/bindings/sound/qcom,lpass-cpu.txt   |  13 +-
 sound/soc/qcom/Kconfig                             |  25 ++-
 sound/soc/qcom/Makefile                            |   5 +
 sound/soc/qcom/apq8016.c                           | 214 ++++++++++++++++++
 sound/soc/qcom/lpass-apq8016.c                     | 243 +++++++++++++++++++++
 sound/soc/qcom/lpass-cpu.c                         | 234 ++++++++++----------
 sound/soc/qcom/lpass-ipq806x.c                     |  95 ++++++++
 sound/soc/qcom/lpass-lpaif-ipq806x.h               | 172 ---------------
 sound/soc/qcom/lpass-lpaif-reg.h                   | 167 ++++++++++++++
 sound/soc/qcom/lpass-platform.c                    | 197 +++++++++++------
 sound/soc/qcom/lpass.h                             |  54 ++++-
 12 files changed, 1121 insertions(+), 359 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-machine.txt
 create mode 100644 sound/soc/qcom/apq8016.c
 create mode 100644 sound/soc/qcom/lpass-apq8016.c
 create mode 100644 sound/soc/qcom/lpass-ipq806x.c
 delete mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
 create mode 100644 sound/soc/qcom/lpass-lpaif-reg.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 88+ messages in thread

* [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check.
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
@ 2015-04-30 17:16 ` Srinivas Kandagatla
  2015-05-04 12:24   ` Mark Brown
  2015-04-30 17:16 ` [RFC PATCH 02/14] ASoC: qcom: remove unnecessary header files Srinivas Kandagatla
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:16 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch remove redundant check after request_resource as ioremap would
do the check anyway.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 6698d05..1e284c6 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -380,10 +380,6 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, drvdata);
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
-	if (!res) {
-		dev_err(&pdev->dev, "%s() error getting resource\n", __func__);
-		return -ENODEV;
-	}
 
 	drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
 	if (IS_ERR((void const __force *)drvdata->lpaif)) {
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 02/14] ASoC: qcom: remove unnecessary header files
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
  2015-04-30 17:16 ` [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check Srinivas Kandagatla
@ 2015-04-30 17:16 ` Srinivas Kandagatla
  2015-05-04 12:24   ` Mark Brown
  2015-04-30 17:16 ` [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
                   ` (14 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:16 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch removes unnecessary header files in lpass cpu and platform
code.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c      | 6 +-----
 sound/soc/qcom/lpass-platform.c | 6 ------
 2 files changed, 1 insertion(+), 11 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 1e284c6..4084295 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -14,12 +14,7 @@
  */
 
 #include <linux/clk.h>
-#include <linux/compiler.h>
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/ioport.h>
 #include <linux/kernel.h>
-#include <linux/mod_devicetable.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
@@ -28,6 +23,7 @@
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
+
 #include "lpass-lpaif-ipq806x.h"
 #include "lpass.h"
 
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 2fa6280..ffc0928 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -13,17 +13,11 @@
  * lpass-platform.c -- ALSA SoC platform driver for QTi LPASS
  */
 
-#include <linux/compiler.h>
-#include <linux/device.h>
 #include <linux/dma-mapping.h>
-#include <linux/err.h>
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/io.h>
 #include <linux/platform_device.h>
-#include <sound/memalloc.h>
-#include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
  2015-04-30 17:16 ` [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check Srinivas Kandagatla
  2015-04-30 17:16 ` [RFC PATCH 02/14] ASoC: qcom: remove unnecessary header files Srinivas Kandagatla
@ 2015-04-30 17:16 ` Srinivas Kandagatla
  2015-05-02 23:57   ` Kenneth Westfield
  2015-04-30 17:17 ` [RFC PATCH 04/14] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:16 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch tries to make the lpass driver more generic by moving the
ipq806x specific bits out of the cpu and platform driver, also allows the
SOC specific drivers to add the correct register offsets.

This patch also renames the register definition header file into more
generic header file.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig               |   9 +-
 sound/soc/qcom/Makefile              |   2 +
 sound/soc/qcom/lpass-cpu.c           | 157 ++++++++++++++++----------------
 sound/soc/qcom/lpass-ipq806x.c       |  82 +++++++++++++++++
 sound/soc/qcom/lpass-lpaif-ipq806x.h | 172 -----------------------------------
 sound/soc/qcom/lpass-lpaif-reg.h     | 167 ++++++++++++++++++++++++++++++++++
 sound/soc/qcom/lpass-platform.c      |  49 ++++++----
 sound/soc/qcom/lpass.h               |  28 ++++++
 8 files changed, 391 insertions(+), 275 deletions(-)
 create mode 100644 sound/soc/qcom/lpass-ipq806x.c
 delete mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
 create mode 100644 sound/soc/qcom/lpass-lpaif-reg.h

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 5f58e4f..ba87e9b 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -14,11 +14,16 @@ config SND_SOC_LPASS_PLATFORM
 	depends on SND_SOC_QCOM
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_IPQ806X
+	tristate
+	depends on SND_SOC_QCOM
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
-	select SND_SOC_LPASS_CPU
-	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_IPQ806X
 	select SND_SOC_MAX98357A
 	help
           Say Y or M if you want add support for SoC audio on the
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index c5ce96c..f8aab91 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,9 +1,11 @@
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
+snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
+obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 
 # Machine
 snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 4084295..74b2245 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -17,14 +17,14 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
-
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -138,7 +138,9 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S),
+			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -162,7 +164,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -177,7 +180,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+			LPAIF_I2SCTL_REG(drvdata->variant, LPAIF_I2S_PORT_MI2S),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -197,7 +200,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant,
+				LPAIF_I2S_PORT_MI2S),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -208,7 +212,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant,
+				LPAIF_I2S_PORT_MI2S),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -220,7 +225,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
+struct snd_soc_dai_ops lpass_cpu_dai_ops = {
 	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
 	.startup	= lpass_cpu_daiops_startup,
 	.shutdown	= lpass_cpu_daiops_shutdown,
@@ -229,41 +234,24 @@ static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
 	.prepare	= lpass_cpu_daiops_prepare,
 	.trigger	= lpass_cpu_daiops_trigger,
 };
+EXPORT_SYMBOL_GPL(lpass_cpu_dai_ops);
 
-static int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
 
 	return ret;
 }
-
-static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
-	.playback = {
-		.stream_name	= "lpass-cpu-playback",
-		.formats	= SNDRV_PCM_FMTBIT_S16 |
-					SNDRV_PCM_FMTBIT_S24 |
-					SNDRV_PCM_FMTBIT_S32,
-		.rates		= SNDRV_PCM_RATE_8000 |
-					SNDRV_PCM_RATE_16000 |
-					SNDRV_PCM_RATE_32000 |
-					SNDRV_PCM_RATE_48000 |
-					SNDRV_PCM_RATE_96000,
-		.rate_min	= 8000,
-		.rate_max	= 96000,
-		.channels_min	= 1,
-		.channels_max	= 8,
-	},
-	.probe	= &lpass_cpu_dai_probe,
-	.ops    = &lpass_cpu_dai_ops,
-};
+EXPORT_SYMBOL_GPL(lpass_cpu_dai_probe);
 
 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 	.name = "lpass-cpu",
@@ -271,27 +259,29 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 
 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-		if (reg == LPAIF_I2SCTL_REG(i))
+	for (i = 0; i < v->i2s_ports; ++i)
+		if (reg == LPAIF_I2SCTL_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-		if (reg == LPAIF_IRQEN_REG(i))
+	for (i = 0; i < v->irq_ports; ++i) {
+		if (reg == LPAIF_IRQEN_REG(v, i))
 			return true;
-		if (reg == LPAIF_IRQCLEAR_REG(i))
+		if (reg == LPAIF_IRQCLEAR_REG(v, i))
 			return true;
 	}
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-		if (reg == LPAIF_RDMACTL_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_RDMACTL_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABASE_REG(i))
+		if (reg == LPAIF_RDMABASE_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABUFF_REG(i))
+		if (reg == LPAIF_RDMABUFF_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMAPER_REG(i))
+		if (reg == LPAIF_RDMAPER_REG(v, i))
 			return true;
 	}
 
@@ -300,29 +290,31 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-		if (reg == LPAIF_I2SCTL_REG(i))
+	for (i = 0; i < v->i2s_ports; ++i)
+		if (reg == LPAIF_I2SCTL_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-		if (reg == LPAIF_IRQEN_REG(i))
+	for (i = 0; i < v->irq_ports; ++i) {
+		if (reg == LPAIF_IRQEN_REG(v, i))
 			return true;
-		if (reg == LPAIF_IRQSTAT_REG(i))
+		if (reg == LPAIF_IRQSTAT_REG(v, i))
 			return true;
 	}
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-		if (reg == LPAIF_RDMACTL_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_RDMACTL_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABASE_REG(i))
+		if (reg == LPAIF_RDMABASE_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABUFF_REG(i))
+		if (reg == LPAIF_RDMABUFF_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMACURR_REG(i))
+		if (reg == LPAIF_RDMACURR_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMAPER_REG(i))
+		if (reg == LPAIF_RDMAPER_REG(v, i))
 			return true;
 	}
 
@@ -331,35 +323,39 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i)
-		if (reg == LPAIF_IRQSTAT_REG(i))
+	for (i = 0; i < v->irq_ports; ++i)
+		if (reg == LPAIF_IRQSTAT_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i)
-		if (reg == LPAIF_RDMACURR_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i)
+		if (reg == LPAIF_RDMACURR_REG(v, i))
 			return true;
 
 	return false;
 }
 
-static const struct regmap_config lpass_cpu_regmap_config = {
+static struct regmap_config lpass_cpu_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
-	.max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX),
 	.writeable_reg = lpass_cpu_regmap_writeable,
 	.readable_reg = lpass_cpu_regmap_readable,
 	.volatile_reg = lpass_cpu_regmap_volatile,
 	.cache_type = REGCACHE_FLAT,
 };
 
-static int lpass_cpu_platform_probe(struct platform_device *pdev)
+int lpass_cpu_platform_probe(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata;
 	struct device_node *dsp_of_node;
 	struct resource *res;
+	struct lpass_variant *variant;
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *match;
 	int ret;
 
 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
@@ -375,6 +371,13 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drvdata);
 
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data)
+		return -EINVAL;
+
+	drvdata->variant = (struct lpass_variant *)match->data;
+	variant = drvdata->variant;
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
 
 	drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
@@ -385,6 +388,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return PTR_ERR((void const __force *)drvdata->lpaif);
 	}
 
+	lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
+						variant->rdma_channels);
+
 	drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
 			&lpass_cpu_regmap_config);
 	if (IS_ERR(drvdata->lpaif_map)) {
@@ -393,6 +399,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return PTR_ERR(drvdata->lpaif_map);
 	}
 
+	if (variant->init)
+		variant->init(pdev);
+
 	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
 	if (IS_ERR(drvdata->mi2s_osr_clk)) {
 		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
@@ -431,7 +440,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
-			&lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1);
+					      &lpass_cpu_comp_driver,
+					      variant->dai_driver,
+					      variant->num_dai);
 	if (ret) {
 		dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
 				__func__, ret);
@@ -451,33 +462,17 @@ err_clk:
 	clk_disable_unprepare(drvdata->ahbix_clk);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(lpass_cpu_platform_probe);
 
-static int lpass_cpu_platform_remove(struct platform_device *pdev)
+int lpass_cpu_platform_remove(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
 
+	if (drvdata->variant->exit)
+		drvdata->variant->exit(pdev);
+
 	clk_disable_unprepare(drvdata->ahbix_clk);
 
 	return 0;
 }
-
-#ifdef CONFIG_OF
-static const struct of_device_id lpass_cpu_device_id[] = {
-	{ .compatible = "qcom,lpass-cpu" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, lpass_cpu_device_id);
-#endif
-
-static struct platform_driver lpass_cpu_platform_driver = {
-	.driver	= {
-		.name		= "lpass-cpu",
-		.of_match_table	= of_match_ptr(lpass_cpu_device_id),
-	},
-	.probe	= lpass_cpu_platform_probe,
-	.remove	= lpass_cpu_platform_remove,
-};
-module_platform_driver(lpass_cpu_platform_driver);
-
-MODULE_DESCRIPTION("QTi LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_GPL(lpass_cpu_platform_remove);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
new file mode 100644
index 0000000..8e9a427
--- /dev/null
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ *
+ * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS
+ * Splited out the IPQ8064 soc specific from lpass-cpu.c
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
+	.playback = {
+		.stream_name	= "lpass-cpu-playback",
+		.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+		.rates		= SNDRV_PCM_RATE_8000 |
+					SNDRV_PCM_RATE_16000 |
+					SNDRV_PCM_RATE_32000 |
+					SNDRV_PCM_RATE_48000 |
+					SNDRV_PCM_RATE_96000,
+		.rate_min	= 8000,
+		.rate_max	= 96000,
+		.channels_min	= 1,
+		.channels_max	= 8,
+	},
+	.probe	= &lpass_cpu_dai_probe,
+	.ops    = &lpass_cpu_dai_ops,
+};
+
+struct lpass_variant ipq806x_data = {
+	.i2sctrl_reg_base	= 0x0010,
+	.i2sctrl_reg_stride	= 0x04,
+	.i2s_ports		= 5,
+	.irq_reg_base		= 0x3000,
+	.irq_reg_stride		= 0x1000,
+	.irq_ports		= 3,
+	.rdma_reg_base		= 0x6000,
+	.rdma_reg_stride	= 0x1000,
+	.rdma_channels		= 4,
+	.dai_driver		= &lpass_cpu_dai_driver,
+	.num_dai		= 1,
+};
+
+static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
+	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
+
+static struct platform_driver lpass_cpu_platform_driver = {
+	.driver	= {
+		.name		= "lpass-cpu",
+		.of_match_table	= of_match_ptr(ipq806x_lpass_cpu_device_id),
+	},
+	.probe	= lpass_cpu_platform_probe,
+	.remove	= lpass_cpu_platform_remove,
+};
+module_platform_driver(lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("QTi LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-ipq806x.h
deleted file mode 100644
index dc423b8..0000000
--- a/sound/soc/qcom/lpass-lpaif-ipq806x.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
- *
- * 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.
- *
- * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS
- */
-
-#ifndef __LPASS_LPAIF_H__
-#define __LPASS_LPAIF_H__
-
-#define LPAIF_BANK_OFFSET		0x1000
-
-/* LPAIF I2S */
-
-#define LPAIF_I2SCTL_REG_BASE		0x0010
-#define LPAIF_I2SCTL_REG_STRIDE		0x4
-#define LPAIF_I2SCTL_REG_ADDR(addr, port) \
-	(LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port)))
-
-enum lpaif_i2s_ports {
-	LPAIF_I2S_PORT_MIN		= 0,
-
-	LPAIF_I2S_PORT_CODEC_SPK	= 0,
-	LPAIF_I2S_PORT_CODEC_MIC	= 1,
-	LPAIF_I2S_PORT_SEC_SPK		= 2,
-	LPAIF_I2S_PORT_SEC_MIC		= 3,
-	LPAIF_I2S_PORT_MI2S		= 4,
-
-	LPAIF_I2S_PORT_MAX		= 4,
-	LPAIF_I2S_PORT_NUM		= 5,
-};
-
-#define LPAIF_I2SCTL_REG(port)		LPAIF_I2SCTL_REG_ADDR(0x0, (port))
-
-#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
-#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
-#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-
-#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
-#define LPAIF_I2SCTL_SPKEN_SHIFT	14
-#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
-#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
-#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
-#define LPAIF_I2SCTL_SPKMODE_NONE	(0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD0	(1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD1	(2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD2	(3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD3	(4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD01	(5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD23	(6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_6CH	(7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_8CH	(8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
-#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
-#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-
-#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
-#define LPAIF_I2SCTL_WSSRC_SHIFT	2
-#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
-#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
-
-#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
-#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
-#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-
-/* LPAIF IRQ */
-
-#define LPAIF_IRQ_REG_BASE		0x3000
-#define LPAIF_IRQ_REG_STRIDE		0x1000
-#define LPAIF_IRQ_REG_ADDR(addr, port) \
-	(LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port)))
-
-enum lpaif_irq_ports {
-	LPAIF_IRQ_PORT_MIN		= 0,
-
-	LPAIF_IRQ_PORT_HOST		= 0,
-	LPAIF_IRQ_PORT_ADSP		= 1,
-
-	LPAIF_IRQ_PORT_MAX		= 2,
-	LPAIF_IRQ_PORT_NUM		= 3,
-};
-
-#define LPAIF_IRQEN_REG(port)		LPAIF_IRQ_REG_ADDR(0x0, (port))
-#define LPAIF_IRQSTAT_REG(port)		LPAIF_IRQ_REG_ADDR(0x4, (port))
-#define LPAIF_IRQCLEAR_REG(port)	LPAIF_IRQ_REG_ADDR(0xC, (port))
-
-#define LPAIF_IRQ_BITSTRIDE		3
-#define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_XRUN(chan)		(2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-
-/* LPAIF DMA */
-
-#define LPAIF_RDMA_REG_BASE		0x6000
-#define LPAIF_RDMA_REG_STRIDE		0x1000
-#define LPAIF_RDMA_REG_ADDR(addr, chan) \
-	(LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan)))
-
-enum lpaif_dma_channels {
-	LPAIF_RDMA_CHAN_MIN		= 0,
-
-	LPAIF_RDMA_CHAN_MI2S		= 0,
-	LPAIF_RDMA_CHAN_PCM0		= 1,
-	LPAIF_RDMA_CHAN_PCM1		= 2,
-
-	LPAIF_RDMA_CHAN_MAX		= 4,
-	LPAIF_RDMA_CHAN_NUM		= 5,
-};
-
-#define LPAIF_RDMACTL_REG(chan)		LPAIF_RDMA_REG_ADDR(0x00, (chan))
-#define LPAIF_RDMABASE_REG(chan)	LPAIF_RDMA_REG_ADDR(0x04, (chan))
-#define	LPAIF_RDMABUFF_REG(chan)	LPAIF_RDMA_REG_ADDR(0x08, (chan))
-#define LPAIF_RDMACURR_REG(chan)	LPAIF_RDMA_REG_ADDR(0x0C, (chan))
-#define	LPAIF_RDMAPER_REG(chan)		LPAIF_RDMA_REG_ADDR(0x10, (chan))
-
-#define LPAIF_RDMACTL_BURSTEN_MASK	0x800
-#define LPAIF_RDMACTL_BURSTEN_SHIFT	11
-#define LPAIF_RDMACTL_BURSTEN_SINGLE	(0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-#define LPAIF_RDMACTL_BURSTEN_INCR4	(1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-
-#define LPAIF_RDMACTL_WPSCNT_MASK	0x700
-#define LPAIF_RDMACTL_WPSCNT_SHIFT	8
-#define LPAIF_RDMACTL_WPSCNT_ONE	(0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_TWO	(1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_THREE	(2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_FOUR	(3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_SIX	(5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_EIGHT	(7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-
-#define LPAIF_RDMACTL_AUDINTF_MASK	0x0F0
-#define LPAIF_RDMACTL_AUDINTF_SHIFT	4
-#define LPAIF_RDMACTL_AUDINTF_NONE	(0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_CODEC	(1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_PCM	(2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_I2S	(3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_MI2S	(4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_HDMI	(5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_PCM	(7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-
-#define LPAIF_RDMACTL_FIFOWM_MASK	0x00E
-#define LPAIF_RDMACTL_FIFOWM_SHIFT	1
-#define LPAIF_RDMACTL_FIFOWM_1		(0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_2		(1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_3		(2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_4		(3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_5		(4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_6		(5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_7		(6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_8		(7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-
-#define LPAIF_RDMACTL_ENABLE_MASK	0x1
-#define LPAIF_RDMACTL_ENABLE_SHIFT	0
-#define LPAIF_RDMACTL_ENABLE_OFF	(0 << LPAIF_RDMACTL_ENABLE_SHIFT)
-#define LPAIF_RDMACTL_ENABLE_ON		(1 << LPAIF_RDMACTL_ENABLE_SHIFT)
-
-#endif /* __LPASS_LPAIF_H__ */
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
new file mode 100644
index 0000000..5541b14
--- /dev/null
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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 __LPASS_LPAIF_REG_H__
+#define __LPASS_LPAIF_REG_H__
+
+
+/* LPAIF I2S */
+
+#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
+	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
+
+enum lpaif_i2s_ports {
+	LPAIF_I2S_PORT_MIN		= 0,
+
+	LPAIF_I2S_PORT_CODEC_SPK	= 0,
+	LPAIF_I2S_PORT_CODEC_MIC	= 1,
+	LPAIF_I2S_PORT_SEC_SPK		= 2,
+	LPAIF_I2S_PORT_SEC_MIC		= 3,
+	LPAIF_I2S_PORT_MI2S		= 4,
+
+	LPAIF_I2S_PORT_MAX		= 4,
+	LPAIF_I2S_PORT_NUM		= 5,
+};
+
+
+#define LPAIF_I2SCTL_REG(v, port)	LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
+#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
+#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
+#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+
+#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
+#define LPAIF_I2SCTL_SPKEN_SHIFT	14
+#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
+#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
+#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
+#define LPAIF_I2SCTL_SPKMODE_NONE	(0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD0	(1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD1	(2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD2	(3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD3	(4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD01	(5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD23	(6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_6CH	(7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_8CH	(8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
+#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
+#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+
+#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
+#define LPAIF_I2SCTL_WSSRC_SHIFT	2
+#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
+#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
+
+#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
+#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
+#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+
+/* LPAIF IRQ */
+#define LPAIF_IRQ_REG_ADDR(v, addr, port) \
+	(v->irq_reg_base + (addr) + v->irq_reg_stride * (port))
+
+enum lpaif_irq_ports {
+	LPAIF_IRQ_PORT_MIN		= 0,
+
+	LPAIF_IRQ_PORT_HOST		= 0,
+	LPAIF_IRQ_PORT_ADSP		= 1,
+
+	LPAIF_IRQ_PORT_MAX		= 2,
+	LPAIF_IRQ_PORT_NUM		= 3,
+};
+
+#define LPAIF_IRQEN_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x0, (port))
+#define LPAIF_IRQSTAT_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
+#define LPAIF_IRQCLEAR_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
+
+#define LPAIF_IRQ_BITSTRIDE		3
+
+#define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_XRUN(chan)		(2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+#define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+/* LPAIF DMA */
+
+#define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
+	(v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
+
+enum lpaif_dma_channels {
+	LPAIF_RDMA_CHAN_MIN		= 0,
+
+	LPAIF_RDMA_CHAN_MI2S		= 0,
+	LPAIF_RDMA_CHAN_PCM0		= 1,
+	LPAIF_RDMA_CHAN_PCM1		= 2,
+
+	LPAIF_RDMA_CHAN_MAX		= 4,
+	LPAIF_RDMA_CHAN_NUM		= 5,
+};
+
+#define LPAIF_RDMACTL_AUDINTF(id)	(id << LPAIF_RDMACTL_AUDINTF_SHIFT)
+
+#define LPAIF_RDMACTL_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x00, (chan))
+#define LPAIF_RDMABASE_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x04, (chan))
+#define	LPAIF_RDMABUFF_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x08, (chan))
+#define LPAIF_RDMACURR_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x0C, (chan))
+#define	LPAIF_RDMAPER_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
+#define	LPAIF_RDMAPERCNT_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x14, (chan))
+
+#define LPAIF_RDMACTL_BURSTEN_MASK	0x800
+#define LPAIF_RDMACTL_BURSTEN_SHIFT	11
+#define LPAIF_RDMACTL_BURSTEN_SINGLE	(0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+#define LPAIF_RDMACTL_BURSTEN_INCR4	(1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+
+#define LPAIF_RDMACTL_WPSCNT_MASK	0x700
+#define LPAIF_RDMACTL_WPSCNT_SHIFT	8
+#define LPAIF_RDMACTL_WPSCNT_ONE	(0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_TWO	(1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_THREE	(2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_FOUR	(3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_SIX	(5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_EIGHT	(7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+
+#define LPAIF_RDMACTL_AUDINTF_MASK	0x0F0
+#define LPAIF_RDMACTL_AUDINTF_SHIFT	4
+#define LPAIF_RDMACTL_AUDINTF_NONE	(0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+#define LPAIF_RDMACTL_AUDINTF_CODEC	(1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+#define LPAIF_RDMACTL_AUDINTF_PCM	(2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+#define LPAIF_RDMACTL_AUDINTF_SEC_I2S	(3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+#define LPAIF_RDMACTL_AUDINTF_MI2S	(4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+#define LPAIF_RDMACTL_AUDINTF_HDMI	(5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+#define LPAIF_RDMACTL_AUDINTF_SEC_PCM	(7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
+
+#define LPAIF_RDMACTL_FIFOWM_MASK	0x00E
+#define LPAIF_RDMACTL_FIFOWM_SHIFT	1
+#define LPAIF_RDMACTL_FIFOWM_1		(0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_2		(1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_3		(2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_4		(3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_5		(4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_6		(5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_7		(6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_8		(7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+
+#define LPAIF_RDMACTL_ENABLE_MASK	0x1
+#define LPAIF_RDMACTL_ENABLE_SHIFT	0
+#define LPAIF_RDMACTL_ENABLE_OFF	(0 << LPAIF_RDMACTL_ENABLE_SHIFT)
+#define LPAIF_RDMACTL_ENABLE_ON		(1 << LPAIF_RDMACTL_ENABLE_SHIFT)
+
+#endif /* __LPASS_LPAIF_REG_H__ */
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index ffc0928..a38e7ec 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -21,7 +21,7 @@
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
@@ -80,6 +80,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	snd_pcm_format_t format = params_format(params);
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
@@ -150,7 +151,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), regval);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -165,10 +166,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -182,10 +184,11 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -194,7 +197,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABUFF_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -203,7 +206,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMAPER_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -212,7 +215,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -229,6 +232,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	switch (cmd) {
@@ -237,7 +241,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		/* clear status before enabling interrupts */
 		ret = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -246,7 +250,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
 		if (ret) {
@@ -256,7 +260,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_ON);
 		if (ret) {
@@ -269,7 +273,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_OFF);
 		if (ret) {
@@ -279,7 +283,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
@@ -298,11 +302,13 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
 	int ret;
 
 	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr);
+			 LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			 &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
 				__func__, ret);
@@ -310,7 +316,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	}
 
 	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr);
+			 LPAIF_RDMACURR_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			 &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
 				__func__, ret);
@@ -347,12 +354,13 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
 	int rv;
 
 	rv = regmap_read(drvdata->lpaif_map,
-			LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
+			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
 	if (rv) {
 		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
 				__func__, rv);
@@ -362,7 +370,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -375,7 +383,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -389,7 +397,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -444,6 +452,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
@@ -464,14 +473,14 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);
+			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 				__func__, ret);
 		return ret;
 	}
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 5c99b3d..5bd2a90 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -43,9 +43,37 @@ struct lpass_data {
 
 	/* interrupts from the low-power audio interface (LPAIF) */
 	int lpaif_irq;
+
+	/* SOC specific variations in the LPASS IP integration */
+	struct lpass_variant *variant;
+};
+
+/* Vairant data per each SOC */
+struct lpass_variant {
+	u32	i2sctrl_reg_base;
+	u32	i2sctrl_reg_stride;
+	u32	i2s_ports;
+	u32	irq_reg_base;
+	u32	irq_reg_stride;
+	u32	irq_ports;
+	u32	rdma_reg_base;
+	u32	rdma_reg_stride;
+	u32	rdma_channels;
+
+	/* SOC specific intialization like clocks */
+	int (*init)(struct platform_device *pdev);
+	int (*exit)(struct platform_device *pdev);
+
+	/* SOC specific dais */
+	struct snd_soc_dai_driver *dai_driver;
+	int num_dai;
 };
 
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
+int lpass_cpu_platform_remove(struct platform_device *pdev);
+int lpass_cpu_platform_probe(struct platform_device *pdev);
+int lpass_cpu_dai_probe(struct snd_soc_dai *dai);
+extern struct snd_soc_dai_ops lpass_cpu_dai_ops;
 
 #endif /* __LPASS_H__ */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 04/14] ASoC: qcom: remove hardcoded i2s port number
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (2 preceding siblings ...)
  2015-04-30 17:16 ` [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-04-30 17:17 ` [RFC PATCH 05/14] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch attempts to remove the hardcoded i2s port number in lpass
driver. Now the the port number comes from the dai id field.

This will allow other SOCs to use different port numbers on the lpass
driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c     | 17 ++++++-----------
 sound/soc/qcom/lpass-ipq806x.c |  1 +
 2 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 74b2245..7aca253 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -138,8 +138,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S),
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
 			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -164,8 +163,7 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -180,7 +178,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(drvdata->variant, LPAIF_I2S_PORT_MI2S),
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -200,8 +198,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(drvdata->variant,
-				LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -212,8 +209,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(drvdata->variant,
-				LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -243,8 +239,7 @@ int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S), 0);
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 8e9a427..0466483 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -29,6 +29,7 @@
 #include "lpass.h"
 
 static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
+	.id	= LPAIF_I2S_PORT_MI2S,
 	.playback = {
 		.stream_name	= "lpass-cpu-playback",
 		.formats	= SNDRV_PCM_FMTBIT_S16 |
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 05/14] ASoC: qcom: remove hardcoded dma channel
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (3 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 04/14] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-04-30 17:17 ` [RFC PATCH 06/14] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch removes hardcoded dma channel value in lpass driver, Now the
dma channel allocation happens in the SOC specific layer. This will
allow different LPASS integrations to use the lpass driver in more
generic way.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-ipq806x.c  | 12 ++++++
 sound/soc/qcom/lpass-platform.c | 93 ++++++++++++++++++++++++++++-------------
 sound/soc/qcom/lpass.h          |  2 +
 3 files changed, 77 insertions(+), 30 deletions(-)

diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 0466483..11a7053 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -49,6 +49,16 @@ static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
 	.ops    = &lpass_cpu_dai_ops,
 };
 
+int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+	return LPAIF_RDMA_CHAN_MI2S;
+}
+
+int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+	return 0;
+}
+
 struct lpass_variant ipq806x_data = {
 	.i2sctrl_reg_base	= 0x0010,
 	.i2sctrl_reg_stride	= 0x04,
@@ -61,6 +71,8 @@ struct lpass_variant ipq806x_data = {
 	.rdma_channels		= 4,
 	.dai_driver		= &lpass_cpu_dai_driver,
 	.num_dai		= 1,
+	.alloc_dma_channel	= ipq806x_lpass_alloc_dma_channel,
+	.free_dma_channel	= ipq806x_lpass_free_dma_channel,
 };
 
 static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a38e7ec..fc08891 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -24,6 +24,11 @@
 #include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
+struct lpass_pcm_data {
+	int rdma_ch;
+	int i2s_port;
+};
+
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
 
@@ -78,6 +83,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
@@ -85,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret;
+	int ret, rdma_port = pcm_data->i2s_port;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -95,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
-			LPAIF_RDMACTL_AUDINTF_MI2S |
+			LPAIF_RDMACTL_AUDINTF(rdma_port) |
 			LPAIF_RDMACTL_FIFOWM_8;
 
 	switch (bitwidth) {
@@ -151,7 +157,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), regval);
+			LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -164,13 +170,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -182,13 +189,14 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABASE_REG(v, ch),
 			runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -197,7 +205,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABUFF_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABUFF_REG(v, ch),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -206,7 +214,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMAPER_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMAPER_REG(v, ch),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -215,7 +223,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMACTL_REG(v, ch),
 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -230,10 +238,11 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		int cmd)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -242,7 +251,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		/* clear status before enabling interrupts */
 		ret = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ALL(ch));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, ret);
@@ -251,8 +260,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ALL(ch),
+				LPAIF_IRQ_ALL(ch));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 					__func__, ret);
@@ -260,7 +269,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, ch),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_ON);
 		if (ret) {
@@ -273,7 +282,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, ch),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_OFF);
 		if (ret) {
@@ -284,7 +293,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
+				LPAIF_IRQ_ALL(ch), 0);
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 					__func__, ret);
@@ -300,15 +309,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	ret = regmap_read(drvdata->lpaif_map,
-			 LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
-			 &base_addr);
+			LPAIF_RDMABASE_REG(v, ch), &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
 				__func__, ret);
@@ -316,8 +325,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	}
 
 	ret = regmap_read(drvdata->lpaif_map,
-			 LPAIF_RDMACURR_REG(v, LPAIF_RDMA_CHAN_MI2S),
-			 &curr_addr);
+			LPAIF_RDMACURR_REG(v, ch), &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
 				__func__, ret);
@@ -355,9 +363,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
-	int rv;
+	int rv, chan = pcm_data->rdma_ch;
 
 	rv = regmap_read(drvdata->lpaif_map,
 			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
@@ -366,12 +375,13 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 				__func__, rv);
 		return IRQ_NONE;
 	}
-	interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);
 
-	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
+	interrupts &= LPAIF_IRQ_ALL(chan);
+
+	if (interrupts & LPAIF_IRQ_PER(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_PER(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -381,10 +391,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
-	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
+	if (interrupts & LPAIF_IRQ_XRUN(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_XRUN(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -395,10 +405,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
-	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
+	if (interrupts & LPAIF_IRQ_ERR(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ERR(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -450,10 +460,26 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	struct snd_pcm *pcm = soc_runtime->pcm;
 	struct snd_pcm_substream *substream =
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	int ret;
+	struct lpass_pcm_data *data;
+
+	data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (v->alloc_dma_channel)
+		data->rdma_ch = v->alloc_dma_channel(drvdata);
+
+	if (IS_ERR_VALUE(data->rdma_ch))
+		return data->rdma_ch;
+
+	data->i2s_port = cpu_dai->driver->id;
+
+	snd_soc_pcm_set_drvdata(soc_runtime, data);
 
 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 	soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
@@ -480,7 +506,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		return ret;
 	}
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -499,6 +525,13 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	struct snd_pcm_substream *substream =
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_data *drvdata =
+		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
+	struct lpass_variant *v = drvdata->variant;
+
+	if (v->free_dma_channel)
+		v->free_dma_channel(drvdata, data->rdma_ch);
 
 	lpass_platform_free_buffer(substream, soc_runtime);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 5bd2a90..80f4b1c 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -63,6 +63,8 @@ struct lpass_variant {
 	/* SOC specific intialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
+	int (*alloc_dma_channel)(struct lpass_data *data);
+	int (*free_dma_channel)(struct lpass_data *data, int ch);
 
 	/* SOC specific dais */
 	struct snd_soc_dai_driver *dai_driver;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 06/14] ASoC: qcom: support bitclk and osrclk per i2s port
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (4 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 05/14] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-04-30 17:17 ` [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant Srinivas Kandagatla
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds support to allow bitclk and osrclk per i2s dai port.
on APQ8016 there are 4 i2s ports each one has its own bit clks.

Without this patch its not possible to support multiple i2s ports in the
lpass driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 53 ++++++++++++++++++++++++++++++----------------
 sound/soc/qcom/lpass.h     |  5 +++--
 2 files changed, 38 insertions(+), 20 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 7aca253..66d068b 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
+	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->id], freq);
 	if (ret)
 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
 				__func__, freq, ret);
@@ -47,18 +47,18 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_prepare_enable(drvdata->mi2s_osr_clk);
+	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
 				__func__, ret);
 		return ret;
 	}
 
-	ret = clk_prepare_enable(drvdata->mi2s_bit_clk);
+	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
 				__func__, ret);
-		clk_disable_unprepare(drvdata->mi2s_osr_clk);
+		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->id]);
 		return ret;
 	}
 
@@ -70,8 +70,8 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
-	clk_disable_unprepare(drvdata->mi2s_bit_clk);
-	clk_disable_unprepare(drvdata->mi2s_osr_clk);
+	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->id]);
+	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -146,7 +146,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
-	ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2);
+	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->id], rate * bitwidth * 2);
 	if (ret) {
 		dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
 				__func__, rate * bitwidth * 2, ret);
@@ -351,7 +351,8 @@ int lpass_cpu_platform_probe(struct platform_device *pdev)
 	struct lpass_variant *variant;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
-	int ret;
+	char clk_name[16];
+	int ret, i;
 
 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
 	if (dsp_of_node) {
@@ -397,18 +398,34 @@ int lpass_cpu_platform_probe(struct platform_device *pdev)
 	if (variant->init)
 		variant->init(pdev);
 
-	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
-	if (IS_ERR(drvdata->mi2s_osr_clk)) {
-		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_osr_clk));
-		return PTR_ERR(drvdata->mi2s_osr_clk);
+	for (i = 0; i < variant->num_dai; i++) {
+		if (variant->num_dai > 1)
+			sprintf(clk_name, "mi2s-osr-clk%d", i);
+		else
+			sprintf(clk_name, "mi2s-osr-clk");
+
+		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(drvdata->mi2s_osr_clk[i])) {
+			dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->mi2s_osr_clk[i]));
+			return PTR_ERR(drvdata->mi2s_osr_clk[i]);
+		}
 	}
 
-	drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");
-	if (IS_ERR(drvdata->mi2s_bit_clk)) {
-		dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_bit_clk));
-		return PTR_ERR(drvdata->mi2s_bit_clk);
+	for (i = 0; i < variant->num_dai; i++) {
+
+		if (variant->num_dai > 1)
+			sprintf(clk_name, "mi2s-bit-clk%d", i);
+		else
+			sprintf(clk_name, "mi2s-bit-clk");
+
+		drvdata->mi2s_bit_clk[i] = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(drvdata->mi2s_bit_clk[i])) {
+			dev_err(&pdev->dev,
+				"%s() error getting mi2s-bit-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
+			return PTR_ERR(drvdata->mi2s_bit_clk[i]);
+		}
 	}
 
 	drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 80f4b1c..6ce2a51 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -22,6 +22,7 @@
 #include <linux/regmap.h>
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
+#define LPASS_MAX_MI2S_PORTS				(4)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -30,10 +31,10 @@ struct lpass_data {
 	struct clk *ahbix_clk;
 
 	/* MI2S system clock */
-	struct clk *mi2s_osr_clk;
+	struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];
 
 	/* MI2S bit clock (derived from system clock by a divider */
-	struct clk *mi2s_bit_clk;
+	struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
 
 	/* low-power audio interface (LPAIF) registers */
 	void __iomem *lpaif;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (5 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 06/14] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-05-02 23:58   ` Kenneth Westfield
  2015-05-04 12:26   ` Mark Brown
  2015-04-30 17:17 ` [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
                   ` (9 subsequent siblings)
  16 siblings, 2 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

Some LPASS integrations like on APQ8016 do not have OSR clk, so adding
no osr clk bit would allow such integrations to use lpass driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 49 +++++++++++++++++++++++++++++-----------------
 sound/soc/qcom/lpass.h     |  2 ++
 2 files changed, 33 insertions(+), 18 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 66d068b..17ad20d 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,6 +33,9 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
+	if (drvdata->variant->no_osr_clk)
+		return 0;
+
 	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->id], freq);
 	if (ret)
 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
@@ -47,18 +50,21 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->id]);
-	if (ret) {
-		dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
-				__func__, ret);
-		return ret;
+	if (!drvdata->variant->no_osr_clk) {
+		ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->id]);
+		if (ret) {
+			dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
+					__func__, ret);
+			return ret;
+		}
 	}
 
 	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
 				__func__, ret);
-		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->id]);
+		if (!drvdata->variant->no_osr_clk)
+			clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->id]);
 		return ret;
 	}
 
@@ -71,7 +77,9 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
 	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->id]);
-	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->id]);
+
+	if (!drvdata->variant->no_osr_clk)
+		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -398,17 +406,22 @@ int lpass_cpu_platform_probe(struct platform_device *pdev)
 	if (variant->init)
 		variant->init(pdev);
 
-	for (i = 0; i < variant->num_dai; i++) {
-		if (variant->num_dai > 1)
-			sprintf(clk_name, "mi2s-osr-clk%d", i);
-		else
-			sprintf(clk_name, "mi2s-osr-clk");
-
-		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev, clk_name);
-		if (IS_ERR(drvdata->mi2s_osr_clk[i])) {
-			dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_osr_clk[i]));
-			return PTR_ERR(drvdata->mi2s_osr_clk[i]);
+	if (!variant->no_osr_clk) {
+		for (i = 0; i < variant->num_dai; i++) {
+			if (variant->num_dai > 1)
+				sprintf(clk_name, "mi2s-osr-clk%d", i);
+			else
+				sprintf(clk_name, "mi2s-osr-clk");
+
+			drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev,
+								clk_name);
+			if (IS_ERR(drvdata->mi2s_osr_clk[i])) {
+				dev_err(&pdev->dev,
+					"%s() error getting mi2s-osr-clk: %ld\n",
+					__func__,
+					PTR_ERR(drvdata->mi2s_osr_clk[i]));
+				return PTR_ERR(drvdata->mi2s_osr_clk[i]);
+			}
 		}
 	}
 
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 6ce2a51..301f784 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -61,6 +61,8 @@ struct lpass_variant {
 	u32	rdma_reg_stride;
 	u32	rdma_channels;
 
+	/* OCR clock is not present in SOCs like APQ8016 */
+	bool	no_osr_clk;
 	/* SOC specific intialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (6 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-05-02 23:59   ` Kenneth Westfield
  2015-04-30 17:17 ` [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds ability to pass dma channel control bits start offset, which
differ in differnet qcom SOCs. On apq8016 dma channel control bits start
after an offset of 1.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 2 +-
 sound/soc/qcom/lpass.h          | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index fc08891..8ab0ac1 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret, rdma_port = pcm_data->i2s_port;
+	int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 301f784..e07ed52 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -61,6 +61,12 @@ struct lpass_variant {
 	u32	rdma_reg_stride;
 	u32	rdma_channels;
 
+	/**
+	 * on SOCs like APQ8016 the channel control bits start
+	 * at different offset to ipq806x
+	 **/
+	u32	rdmactl_audif_start;
+
 	/* OCR clock is not present in SOCs like APQ8016 */
 	bool	no_osr_clk;
 	/* SOC specific intialization like clocks */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (7 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-05-03  0:00   ` Kenneth Westfield
  2015-04-30 17:17 ` [RFC PATCH 10/14] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds ablity to lpass driver to handle interrupt per dma
channel. Without this patch its not possible to use multipl ports on the
lpass.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 89 +++++++++++++++++++++++++----------------
 sound/soc/qcom/lpass.h          |  4 ++
 2 files changed, 58 insertions(+), 35 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 8ab0ac1..c5907d5 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -356,27 +356,15 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = {
 	.mmap		= lpass_platform_pcmops_mmap,
 };
 
-static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+static irqreturn_t lpass_dma_interrupt_handler(
+			struct snd_pcm_substream *substream,
+			struct lpass_data *drvdata,
+			int chan, u32 interrupts)
 {
-	struct snd_pcm_substream *substream = data;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
-	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
-	int rv, chan = pcm_data->rdma_ch;
-
-	rv = regmap_read(drvdata->lpaif_map,
-			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
-	if (rv) {
-		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
-				__func__, rv);
-		return IRQ_NONE;
-	}
-
-	interrupts &= LPAIF_IRQ_ALL(chan);
+	int rv;
 
 	if (interrupts & LPAIF_IRQ_PER(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
@@ -422,6 +410,30 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	return ret;
 }
 
+static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->lpaif_map,
+			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
+	if (rv) {
+		pr_err("%s() error reading from irqstat reg: %d\n",
+				__func__, rv);
+		return IRQ_NONE;
+	}
+
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++)
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan])
+			lpass_dma_interrupt_handler(drvdata->substream[chan],
+						    drvdata, chan, irqs);
+
+	return IRQ_HANDLED;
+}
+
 static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
 		struct snd_soc_pcm_runtime *soc_runtime)
 {
@@ -477,6 +489,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (IS_ERR_VALUE(data->rdma_ch))
 		return data->rdma_ch;
 
+	drvdata->substream[data->rdma_ch] = substream;
 	data->i2s_port = cpu_dai->driver->id;
 
 	snd_soc_pcm_set_drvdata(soc_runtime, data);
@@ -488,29 +501,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (ret)
 		return ret;
 
-	ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
-			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
-			"lpass-irq-lpaif", substream);
-	if (ret) {
-		dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
-				__func__, ret);
-		goto err_buf;
-	}
-
-	/* ensure audio hardware is disabled */
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
-	if (ret) {
-		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
-				__func__, ret);
-		return ret;
-	}
 	ret = regmap_write(drvdata->lpaif_map,
 			LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
-		return ret;
+		goto err_buf;
 	}
 
 	return 0;
@@ -530,6 +526,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_variant *v = drvdata->variant;
 
+	drvdata->substream[data->rdma_ch] = NULL;
+
 	if (v->free_dma_channel)
 		v->free_dma_channel(drvdata, data->rdma_ch);
 
@@ -545,6 +543,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = {
 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct lpass_variant *v = drvdata->variant;
+	int ret;
 
 	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
 	if (drvdata->lpaif_irq < 0) {
@@ -553,6 +553,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
+			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
+			"lpass-irq-lpaif", drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() irq request failed: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	/* ensure audio hardware is disabled */
+	ret = regmap_write(drvdata->lpaif_map,
+			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+
 	return devm_snd_soc_register_platform(&pdev->dev,
 			&lpass_platform_driver);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index e07ed52..c3016fe 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -23,6 +23,7 @@
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
 #define LPASS_MAX_MI2S_PORTS				(4)
+#define LPASS_MAX_DMA_CHANNELS			(8)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -47,6 +48,9 @@ struct lpass_data {
 
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
+
+	/* used it for handling interrupt per dma channel */
+	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 };
 
 /* Vairant data per each SOC */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 10/14] ASoC: qcom: add bit map to track static dma channel allocations
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (8 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-04-30 17:17 ` [RFC PATCH 11/14] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds dma channel bit mask to lpass data to keep track of dma
channel allocations. This flag would be used in apq8016 lpass driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index c3016fe..82708d1 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -49,6 +49,9 @@ struct lpass_data {
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
 
+	/* bit map to keep track of static channel allocations */
+	unsigned long rdma_ch_bit_map;
+
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 11/14] ASoC: qcom: Add apq8016 lpass driver support
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (9 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 10/14] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
@ 2015-04-30 17:17 ` Srinivas Kandagatla
  2015-04-30 17:18 ` [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds apq8016 lpass driver support. APQ8016 has 4 MI2S which
can be routed to one internal codec and 2 external codec interfaces.

Primary, Secondary, Quaternary I2S can do Rx(playback) and Tertiary and
Quaternary can do Tx(capture).

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig         |   7 ++
 sound/soc/qcom/Makefile        |   2 +
 sound/soc/qcom/lpass-apq8016.c | 243 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/qcom/lpass.h         |   4 +
 4 files changed, 256 insertions(+)
 create mode 100644 sound/soc/qcom/lpass-apq8016.c

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index ba87e9b..2a06d1e 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,13 @@ config SND_SOC_LPASS_IPQ806X
 	select SND_SOC_LPASS_CPU
 	select SND_SOC_LPASS_PLATFORM
 
+config SND_SOC_LPASS_APQ8016
+	tristate
+	depends on SND_SOC_QCOM
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index f8aab91..ac76308 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -2,10 +2,12 @@
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
+snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
+obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 
 # Machine
 snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
new file mode 100644
index 0000000..8e545e0
--- /dev/null
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ *
+ * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
+ *
+ */
+
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include <dt-bindings/sound/apq8016-lpass.h>
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
+	[MI2S_PRIMARY] =  {
+		.id = MI2S_PRIMARY,
+		.name = "Primary MI2S",
+		.playback = {
+			.stream_name	= "Primary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &lpass_cpu_dai_probe,
+		.ops    = &lpass_cpu_dai_ops,
+	},
+	[MI2S_SECONDARY] =  {
+		.id = MI2S_SECONDARY,
+		.name = "Secondary MI2S",
+		.playback = {
+			.stream_name	= "Secondary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &lpass_cpu_dai_probe,
+		.ops    = &lpass_cpu_dai_ops,
+	},
+	[MI2S_TERTIARY] =  {
+		.id = MI2S_TERTIARY,
+		.name = "Tertiary MI2S",
+		.capture = {
+			.stream_name	= "Tertiary Capture",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &lpass_cpu_dai_probe,
+		.ops    = &lpass_cpu_dai_ops,
+	},
+	[MI2S_QUATERNARY] =  {
+		.id = MI2S_QUATERNARY,
+		.name = "Quatenary MI2S",
+		.playback = {
+			.stream_name	= "Quatenary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.capture = {
+			.stream_name	= "Quatenary Capture",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &lpass_cpu_dai_probe,
+		.ops    = &lpass_cpu_dai_ops,
+	},
+};
+
+static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+	struct lpass_variant *v = drvdata->variant;
+	int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,
+					v->rdma_channels);
+
+	if (chan >= v->rdma_channels)
+		return -EBUSY;
+
+	set_bit(chan, &drvdata->rdma_ch_bit_map);
+
+	return chan;
+}
+
+static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+	clear_bit(chan, &drvdata->rdma_ch_bit_map);
+
+	return 0;
+}
+
+static int apq8016_lpass_init(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	drvdata->pcnoc_mport_clk = of_clk_get_by_name(np, "pcnoc-mport-clk");
+	if (IS_ERR(drvdata->pcnoc_mport_clk)) {
+		dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->pcnoc_mport_clk));
+		return PTR_ERR(drvdata->pcnoc_mport_clk);
+	}
+
+	ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	drvdata->pcnoc_sway_clk = of_clk_get_by_name(np, "pcnoc-sway-clk");
+	if (IS_ERR(drvdata->pcnoc_sway_clk)) {
+		dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->pcnoc_sway_clk));
+		return PTR_ERR(drvdata->pcnoc_sway_clk);
+	}
+
+	ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int apq8016_lpass_exit(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(drvdata->pcnoc_mport_clk);
+	clk_disable_unprepare(drvdata->pcnoc_sway_clk);
+
+	return 0;
+}
+
+
+struct lpass_variant apq8016_data = {
+	.i2sctrl_reg_base	= 0x1000,
+	.i2sctrl_reg_stride	= 0x1000,
+	.i2s_ports		= 4,
+	.irq_reg_base		= 0x6000,
+	.irq_reg_stride		= 0x1000,
+	.irq_ports		= 3,
+	.rdma_reg_base		= 0x8400,
+	.rdma_reg_stride	= 0x1000,
+	.rdma_channels		= 2,
+	.rdmactl_audif_start	= 1,
+	.no_osr_clk		= true,
+	.dai_driver		= apq8016_lpass_cpu_dai_driver,
+	.num_dai		= ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
+	.init			= apq8016_lpass_init,
+	.exit			= apq8016_lpass_exit,
+	.alloc_dma_channel	= apq8016_lpass_alloc_dma_channel,
+	.free_dma_channel	= apq8016_lpass_free_dma_channel,
+};
+
+static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
+	{ .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
+
+static struct platform_driver lpass_cpu_platform_driver = {
+	.driver	= {
+		.name		= "apq8016-lpass-cpu",
+		.of_match_table	= of_match_ptr(apq8016_lpass_cpu_device_id),
+	},
+	.probe	= lpass_cpu_platform_probe,
+	.remove	= lpass_cpu_platform_remove,
+};
+module_platform_driver(lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 82708d1..3346080 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -54,6 +54,10 @@ struct lpass_data {
 
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
+
+	/* 8016 specific */
+	struct clk *pcnoc_mport_clk;
+	struct clk *pcnoc_sway_clk;
 };
 
 /* Vairant data per each SOC */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (10 preceding siblings ...)
  2015-04-30 17:17 ` [RFC PATCH 11/14] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
@ 2015-04-30 17:18 ` Srinivas Kandagatla
  2015-05-03  0:01   ` Kenneth Westfield
  2015-04-30 17:18 ` [RFC PATCH 13/14] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:18 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds apq8016 machine driver support. This patch was tested on
two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
features.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig   |   9 ++
 sound/soc/qcom/Makefile  |   1 +
 sound/soc/qcom/apq8016.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 224 insertions(+)
 create mode 100644 sound/soc/qcom/apq8016.c

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 2a06d1e..7227383 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -35,3 +35,12 @@ config SND_SOC_STORM
 	help
           Say Y or M if you want add support for SoC audio on the
           Qualcomm Technologies IPQ806X-based Storm board.
+
+config SND_SOC_APQ8016
+	tristate "SoC Audio support for APQ8016 based platforms"
+	depends on SND_SOC_QCOM || ARCH_QCOM || COMPILE_TEST
+	select SND_SOC_LPASS_APQ8016
+	help
+          Support for Qualcomm Technologies LPASS audio block in
+          APQ8016 SOC-based systems.
+          Say Y if you want to use audio devices on MI2S
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index ac76308..589ee9b 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -13,3 +13,4 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 snd-soc-storm-objs := storm.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
+obj-$(CONFIG_SND_SOC_APQ8016) += apq8016.o
diff --git a/sound/soc/qcom/apq8016.c b/sound/soc/qcom/apq8016.c
new file mode 100644
index 0000000..cfb6930
--- /dev/null
+++ b/sound/soc/qcom/apq8016.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+struct apq8016_card_data {
+	void __iomem *mic_iomux;
+	void __iomem *spkr_iomux;
+	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
+};
+
+#define MIC_CTRL_QUA_WS_SLAVE_SEL_10	BIT(17)
+#define MIC_CTRL_TLMM_SCLK_EN		BIT(1)
+#define	SPKR_CTL_PRI_WS_SLAVE_SEL_11	(BIT(17) | BIT(16))
+
+static int msm_ext_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct apq8016_card_data *pdata = snd_soc_card_get_drvdata(card);
+
+	/* Configure the Quat MI2S to TLMM */
+	writel(readl(pdata->mic_iomux) |
+			MIC_CTRL_QUA_WS_SLAVE_SEL_10 |
+			MIC_CTRL_TLMM_SCLK_EN,
+			pdata->mic_iomux);
+
+	return 0;
+}
+
+static int msm_int_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_card *card = rtd->card;
+	struct apq8016_card_data *pdata = snd_soc_card_get_drvdata(card);
+
+	writel(readl(pdata->spkr_iomux) | SPKR_CTL_PRI_WS_SLAVE_SEL_11,
+		pdata->spkr_iomux);
+
+	return 0;
+}
+static struct snd_soc_ops qcom_internal_codec_soc_ops = {
+	.startup	= msm_int_mi2s_snd_startup,
+};
+
+static struct snd_soc_ops qcom_external_codec_soc_ops = {
+	.startup	= msm_ext_mi2s_snd_startup,
+};
+
+static struct snd_soc_card qcom_soc_card = {
+	.name	= "apq8016",
+};
+
+static struct apq8016_card_data *qcom_parse_of(struct snd_soc_card *card)
+{
+	int num_links;
+	struct device *dev = card->dev;
+	struct snd_soc_dai_link *dai_link;
+	struct device_node *np, *codec, *cpu, *node  = dev->of_node;
+	struct apq8016_card_data *data;
+	char *name;
+	int ret;
+
+	/* Populate links */
+	num_links = of_get_child_count(node);
+
+	/* Allocate the private data and the DAI link array */
+	data = devm_kzalloc(dev, sizeof(*data) + sizeof(*dai_link) * num_links,
+			    GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	card->dai_link	= &data->dai_link[0];
+	card->num_links	= num_links;
+
+	dai_link = data->dai_link;
+
+	for_each_child_of_node(node, np) {
+		cpu = of_get_child_by_name(np, "cpu");
+		codec = of_get_child_by_name(np, "codec");
+
+		if (!cpu || !codec) {
+			dev_err(dev, "Can't find cpu/codec DT node\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		dai_link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+		if (!dai_link->cpu_of_node) {
+			dev_err(card->dev, "error getting cpu phandle\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		dai_link->codec_of_node = of_parse_phandle(codec,
+							   "sound-dai",
+							   0);
+		if (!dai_link->codec_of_node) {
+			dev_err(card->dev, "error getting codec phandle\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		ret = snd_soc_of_get_dai_name(cpu, &dai_link->cpu_dai_name);
+		if (ret)
+			return ERR_PTR(ret);
+
+		ret = snd_soc_of_get_dai_name(codec, &dai_link->codec_dai_name);
+		if (ret)
+			return ERR_PTR(ret);
+
+		dai_link->platform_of_node = dai_link->cpu_of_node;
+		/* For now we only support playback */
+		dai_link->playback_only = true;
+
+		if (of_property_read_bool(np, "external")) {
+			name = "HDMI";
+			dai_link->ops = &qcom_external_codec_soc_ops;
+
+		} else {
+			name = "Headset";
+			dai_link->ops = &qcom_internal_codec_soc_ops;
+		}
+
+		dai_link->name = dai_link->stream_name = name;
+
+		dai_link++;
+	}
+
+	return data;
+}
+
+static int qcom_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card = &qcom_soc_card;
+	struct apq8016_card_data *data;
+	struct resource *res;
+	int ret;
+
+	card->dev = dev;
+	data = qcom_parse_of(card);
+	if (PTR_ERR(data)) {
+		dev_err(&pdev->dev, "Error resolving dai links: %d\n",
+			PTR_ERR(data));
+		return PTR_ERR(data);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux");
+	data->mic_iomux = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->mic_iomux))
+		return PTR_ERR(data->mic_iomux);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spkr-iomux");
+	data->spkr_iomux = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->spkr_iomux))
+		return PTR_ERR(data->spkr_iomux);
+
+	platform_set_drvdata(pdev, data);
+	snd_soc_card_set_drvdata(card, data);
+
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret) {
+		dev_err(&pdev->dev, "Error parsing card name: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret == -EPROBE_DEFER) {
+		card->dev = NULL;
+		return ret;
+	} else if (ret) {
+		dev_err(&pdev->dev, "Error registering soundcard: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id qcom_device_id[]  = {
+	{ .compatible = "qcom,apq8016-sndcard" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, qcom_device_id);
+
+static struct platform_driver qcom_platform_driver = {
+	.driver = {
+		.name = "qcom-apq8016",
+		.of_match_table = of_match_ptr(qcom_device_id),
+	},
+	.probe = qcom_platform_probe,
+};
+module_platform_driver(qcom_platform_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 13/14] ASoC: qcom: Document apq8016 bindings.
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (11 preceding siblings ...)
  2015-04-30 17:18 ` [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
@ 2015-04-30 17:18 ` Srinivas Kandagatla
  2015-04-30 17:18 ` [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings Srinivas Kandagatla
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:18 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch updates lpass bindings with apq8016 specific bindings.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index e00732d..21c6483 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
 
 Required properties:
 
-- compatible		: "qcom,lpass-cpu"
+- compatible		: "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
 - clocks		: Must contain an entry for each entry in clock-names.
 - clock-names		: A list which must include the following entries:
 				* "ahbix-clk"
 				* "mi2s-osr-clk"
 				* "mi2s-bit-clk"
+			: required clocks for "qcom,lpass-cpu-apq8016"
+				* "ahbix-clk"
+				* "mi2s-bit-clk0"
+				* "mi2s-bit-clk1"
+				* "mi2s-bit-clk2"
+				* "mi2s-bit-clk3"
+				* "pcnoc-mport-clk"
+				* "pcnoc-sway-clk"
+
 - interrupts		: Must contain an entry for each entry in
 			  interrupt-names.
 - interrupt-names	: A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
 - reg-names		: A list which must include the following entries:
 				* "lpass-lpaif"
 
+
+
 Optional properties:
 
 - qcom,adsp		: Phandle for the audio DSP node
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (12 preceding siblings ...)
  2015-04-30 17:18 ` [RFC PATCH 13/14] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
@ 2015-04-30 17:18 ` Srinivas Kandagatla
  2015-05-03  0:03   ` Kenneth Westfield
  2015-05-02 23:57 ` [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-04-30 17:18 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds bindings for apq8016 machine driver.
On APQ8016 4 MI2S can be configured to different sinks like internal
codec/external codec, this connection is controlled via 2 iomux
registers.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../bindings/sound/qcom,apq8016-machine.txt        | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-machine.txt

diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-machine.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-machine.txt
new file mode 100644
index 0000000..de697b8
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-machine.txt
@@ -0,0 +1,61 @@
+* Qualcomm Technologies APQ8016 ASoC machine driver
+
+This node models the Qualcomm Technologies APQ8016 ASoC machine driver
+
+Required properties:
+
+- compatible		: "qcom,apq8016-sndcard"
+
+- pinctrl-N		: One property must exist for each entry in
+			  pinctrl-names.  See ../pinctrl/pinctrl-bindings.txt
+			  for details of the property values.
+- pinctrl-names		: Must contain a "default" entry.
+- reg			: Must contain an address for each entry in reg-names.
+- reg-names		: A list which must include the following entries:
+				* "mic-iomux"
+				* "spkr-iomux"
+- qcom,model		: Name of the sound card.
+
+Dai-link subnode properties and subnodes:
+
+Required dai-link subnodes:
+
+- cpu					: CPU   sub-node
+- codec					: CODEC sub-node
+
+Required CPU/CODEC subnodes properties:
+
+-sound-dai		: phandle and port of CPU/CODEC
+-capture-dai		: phandle and port of CPU/CODEC
+
+Optional CPU/CODEC subnodes properties:
+- external	: flag to indicate if the I2S is connected to external codec
+Example:
+
+sound: sound {
+	compatible = "qcom,apq8016-sndcard";
+	reg = <0x07702000 0x4>, <0x07702004 0x4>;
+	reg-names = "mic-iomux", "spkr-iomux";
+	qcom,model = "DB410c";
+
+	/* I2S - Internal codec */
+	internal-dai-link@0 {
+		cpu { /* PRIMARY */
+			sound-dai = <&lpass MI2S_PRIMARY>;
+		};
+		codec {
+			sound-dai = <&wcd_codec 0>;
+		};
+	};
+
+	/* External Primary or External Secondary -ADV7533 HDMI */
+	external-dai-link@0 {
+		external;
+		cpu { /* QUAT */
+			sound-dai = <&lpass MI2S_QUATERNARY>;
+		};
+		codec {
+			sound-dai = <&adv_bridge 0>;
+		};
+	};
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (13 preceding siblings ...)
  2015-04-30 17:18 ` [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings Srinivas Kandagatla
@ 2015-05-02 23:57 ` Kenneth Westfield
  2015-05-06  5:47   ` Kenneth Westfield
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
  16 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-02 23:57 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:15:48PM +0100, Srinivas Kandagatla wrote:
> Hi All,
> 
> This patchset adds apq8016 audio support into lpass driver. Existing Lpass
> driver can not be used as-it-is for apq8016 as it contains code specific to
> ipq806x. Also the driver only supports single i2s port, single dma channel and
> single bitclk control.
> 
> APQ8016 has 4 MI2S( Primary, Secondary, Tertiary, Quaternary) which can be routed
> to internal wcd codec or external codecs. This routing is controlled by 2 mux
> registers.
> 
> This patch series firstly re-organizes the lpass driver such that the SOC
> specific bits are moved away from the driver. And secondly the SOC specifics
> are now passed as lpass variant data which would include various register
> offsets, dma channel allocations and SOC specific clock handling.
> 
> Finally the patchset add apq8016 lpass and machine driver.
> 
> This patchset also has two trivial cleanup patches which are to do with
> redundant checks and removing unnecessary header files.
> 
> All these patches are tested for HDMI audio via adv7533 bridge and Analog audio
> on APQ8016-SBC and msm8916-mtp boards. I dont have access to ipq806x boards to
> test these patches.
> 
> This is very first version of the patches which was developed with very
> mimimal/no access to IP documentation. I would like to get your opinon on the
> over all approch.
> 
> 
> Kenneth/Patrick,
> 	Could you please try these patches on storm board?

I will test the patches and let you know by Wednesday.  Also, I posted
some comments, but Patrick should be posting his comments separately
later next week.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-04-30 17:16 ` [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
@ 2015-05-02 23:57   ` Kenneth Westfield
  2015-05-05  5:19     ` Kenneth Westfield
  2015-05-05  7:16     ` Srinivas Kandagatla
  0 siblings, 2 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-02 23:57 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:16:53PM +0100, Srinivas Kandagatla wrote:
> This patch tries to make the lpass driver more generic by moving the
> ipq806x specific bits out of the cpu and platform driver, also allows the
> SOC specific drivers to add the correct register offsets.
> 
> This patch also renames the register definition header file into more
> generic header file.

> diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
> new file mode 100644
> index 0000000..8e9a427
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-ipq806x.c

> +static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
> +	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);

Surround with #ifdef CONFIG_OF?

> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
> new file mode 100644
> index 0000000..5541b14
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-lpaif-reg.h

> +#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
> +	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))

Could all of these variant-related macros be eliminated by using the
regmap_fields_* accessor functions, instead of the regmap_* functions?

> +enum lpaif_i2s_ports {
> +	LPAIF_I2S_PORT_MIN		= 0,
> +
> +	LPAIF_I2S_PORT_CODEC_SPK	= 0,
> +	LPAIF_I2S_PORT_CODEC_MIC	= 1,
> +	LPAIF_I2S_PORT_SEC_SPK		= 2,
> +	LPAIF_I2S_PORT_SEC_MIC		= 3,
> +	LPAIF_I2S_PORT_MI2S		= 4,
> +
> +	LPAIF_I2S_PORT_MAX		= 4,
> +	LPAIF_I2S_PORT_NUM		= 5,
> +};

These port mappings here...

> +enum lpaif_irq_ports {
> +	LPAIF_IRQ_PORT_MIN		= 0,
> +
> +	LPAIF_IRQ_PORT_HOST		= 0,
> +	LPAIF_IRQ_PORT_ADSP		= 1,
> +
> +	LPAIF_IRQ_PORT_MAX		= 2,
> +	LPAIF_IRQ_PORT_NUM		= 3,
> +};

...here...

> +enum lpaif_dma_channels {
> +	LPAIF_RDMA_CHAN_MIN		= 0,
> +
> +	LPAIF_RDMA_CHAN_MI2S		= 0,
> +	LPAIF_RDMA_CHAN_PCM0		= 1,
> +	LPAIF_RDMA_CHAN_PCM1		= 2,
> +
> +	LPAIF_RDMA_CHAN_MAX		= 4,
> +	LPAIF_RDMA_CHAN_NUM		= 5,
> +};

...and here can be SOC-specific.  Should move them to the SOC-specific
files.

> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
> index 5c99b3d..5bd2a90 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h

>  /* register the platform driver from the CPU DAI driver */
>  int asoc_qcom_lpass_platform_register(struct platform_device *);
> +int lpass_cpu_platform_remove(struct platform_device *pdev);
> +int lpass_cpu_platform_probe(struct platform_device *pdev);
> +int lpass_cpu_dai_probe(struct snd_soc_dai *dai);
> +extern struct snd_soc_dai_ops lpass_cpu_dai_ops;

Prefix with asoc_qcom_ to reduce chance of collisions.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant
  2015-04-30 17:17 ` [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant Srinivas Kandagatla
@ 2015-05-02 23:58   ` Kenneth Westfield
  2015-05-05  7:17     ` Srinivas Kandagatla
  2015-05-04 12:26   ` Mark Brown
  1 sibling, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-02 23:58 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:17:24PM +0100, Srinivas Kandagatla wrote:
> Some LPASS integrations like on APQ8016 do not have OSR clk, so adding
> no osr clk bit would allow such integrations to use lpass driver.

Going forward, as the code is generalized, perhaps having an enable flag
for each clock, rather than a flag that negates an existing clock?
Or checking that the clock pointer is NULL after probing would be the
indication?

>  sound/soc/qcom/lpass-cpu.c | 49 +++++++++++++++++++++++++++++-----------------
>  sound/soc/qcom/lpass.h     |  2 ++
>  2 files changed, 33 insertions(+), 18 deletions(-)

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data
  2015-04-30 17:17 ` [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
@ 2015-05-02 23:59   ` Kenneth Westfield
  2015-05-05  7:16     ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-02 23:59 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:17:32PM +0100, Srinivas Kandagatla wrote:
> This patch adds ability to pass dma channel control bits start offset, which
> differ in differnet qcom SOCs. On apq8016 dma channel control bits start
> after an offset of 1.

Alot of the SOCs have similar small differences in the LPASS register
map.  For now, this is fine, but we will probably want to add some
system of quirks to handle these differences; as more SOCs drivers
are implemented.

>  sound/soc/qcom/lpass-platform.c | 2 +-
>  sound/soc/qcom/lpass.h          | 6 ++++++
>  2 files changed, 7 insertions(+), 1 deletion(-)

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel
  2015-04-30 17:17 ` [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
@ 2015-05-03  0:00   ` Kenneth Westfield
  2015-05-05  7:17     ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-03  0:00 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:17:42PM +0100, Srinivas Kandagatla wrote:
> This patch adds ablity to lpass driver to handle interrupt per dma
> channel. Without this patch its not possible to use multipl ports on the
> lpass.
 
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index 8ab0ac1..c5907d5 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c

> -static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
> +static irqreturn_t lpass_dma_interrupt_handler(
> +			struct snd_pcm_substream *substream,
> +			struct lpass_data *drvdata,
> +			int chan, u32 interrupts)
>  {
> -	struct snd_pcm_substream *substream = data;
>  	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
> -	struct lpass_data *drvdata =
> -		snd_soc_platform_get_drvdata(soc_runtime->platform);
>  	struct lpass_variant *v = drvdata->variant;
> -	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
> -	unsigned int interrupts;
>  	irqreturn_t ret = IRQ_NONE;
> -	int rv, chan = pcm_data->rdma_ch;
> -
> -	rv = regmap_read(drvdata->lpaif_map,
> -			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
> -	if (rv) {
> -		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
> -				__func__, rv);
> -		return IRQ_NONE;
> -	}
> -
> -	interrupts &= LPAIF_IRQ_ALL(chan);
> +	int rv;
>  
>  	if (interrupts & LPAIF_IRQ_PER(chan)) {
>  		rv = regmap_write(drvdata->lpaif_map,
> @@ -422,6 +410,30 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
>  	return ret;

You are returning the ISR result here...

>  }
>  
> +static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
> +{
> +	struct lpass_data *drvdata = data;
> +	struct lpass_variant *v = drvdata->variant;
> +	unsigned int irqs;
> +	int rv, chan;
> +
> +	rv = regmap_read(drvdata->lpaif_map,
> +			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
> +	if (rv) {
> +		pr_err("%s() error reading from irqstat reg: %d\n",
> +				__func__, rv);
> +		return IRQ_NONE;
> +	}
> +
> +	/* Handle per channel interrupts */
> +	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++)
> +		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan])
> +			lpass_dma_interrupt_handler(drvdata->substream[chan],
> +						    drvdata, chan, irqs);

...but ignoring the result here and always returning HANDLED.

> +
> +	return IRQ_HANDLED;
> +}
> +

>  int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>  {
>  	struct lpass_data *drvdata = platform_get_drvdata(pdev);
> +	struct lpass_variant *v = drvdata->variant;
> +	int ret;
>  
>  	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
>  	if (drvdata->lpaif_irq < 0) {
> @@ -553,6 +553,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>  		return -ENODEV;
>  	}
>  
> +	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
> +			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
> +			"lpass-irq-lpaif", drvdata);
> +	if (ret) {
> +		dev_err(&pdev->dev, "%s() irq request failed: %d\n",
> +				__func__, ret);
> +		return ret;
> +	}
> +
> +	/* ensure audio hardware is disabled */
> +	ret = regmap_write(drvdata->lpaif_map,
> +			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
> +	if (ret) {
> +		dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
> +				__func__, ret);
> +		return ret;
> +	}

Looking at this, it may be safer to disable the interrupt sources before
getting/enabling the interrupt, i.e. do the regmap_write first, then
devm_request_irq.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support
  2015-04-30 17:18 ` [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
@ 2015-05-03  0:01   ` Kenneth Westfield
  2015-05-05  7:17     ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-03  0:01 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:18:07PM +0100, Srinivas Kandagatla wrote:
> This patch adds apq8016 machine driver support. This patch was tested on
> two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
> features.

apq8016 refers to the SOC, whereas machine drivers are board-specific.
Better to reference the board (or SOC-Codec combo) instead.

> ---
>  sound/soc/qcom/Kconfig   |   9 ++
>  sound/soc/qcom/Makefile  |   1 +
>  sound/soc/qcom/apq8016.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 224 insertions(+)
>  create mode 100644 sound/soc/qcom/apq8016.c


-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings
  2015-04-30 17:18 ` [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings Srinivas Kandagatla
@ 2015-05-03  0:03   ` Kenneth Westfield
  2015-05-03  3:59     ` Kenneth Westfield
  2015-05-05  7:17     ` Srinivas Kandagatla
  0 siblings, 2 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-03  0:03 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Thu, Apr 30, 2015 at 06:18:26PM +0100, Srinivas Kandagatla wrote:
> This patch adds bindings for apq8016 machine driver.
> On APQ8016 4 MI2S can be configured to different sinks like internal
> codec/external codec, this connection is controlled via 2 iomux
> registers.
> 
> +sound: sound {
> +	compatible = "qcom,apq8016-sndcard";
> +	reg = <0x07702000 0x4>, <0x07702004 0x4>;
> +	reg-names = "mic-iomux", "spkr-iomux";
> +	qcom,model = "DB410c";
> +
> +	/* I2S - Internal codec */
> +	internal-dai-link@0 {
> +		cpu { /* PRIMARY */
> +			sound-dai = <&lpass MI2S_PRIMARY>;
> +		};
> +		codec {
> +			sound-dai = <&wcd_codec 0>;
> +		};
> +	};
> +
> +	/* External Primary or External Secondary -ADV7533 HDMI */
> +	external-dai-link@0 {
> +		external;
> +		cpu { /* QUAT */
> +			sound-dai = <&lpass MI2S_QUATERNARY>;
> +		};
> +		codec {
> +			sound-dai = <&adv_bridge 0>;
> +		};
> +	};
> +};

OK, although I will need to double-check this with the spec, it seems
(from the patches) that there are 4 I2S ports, 2 of which are being
used.  Usually, multi-channel audio is sent to the primary dai (which
is MI2S), which then gets sent to the other ports by HW.  If that holds
true for this SOC, then the external cpu dai should be labelled I2S,
not MI2S.  If not, then both should be labelled as I2S (and the DAI
channel constraints should be reduced to 1-2).

Looking at patch 12, the internal DAI is labelled Headset and the
external DAI is labelled HDMI.  I will check the spec to see if the QUAT
I2S port can handle multi-channel.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings
  2015-05-03  0:03   ` Kenneth Westfield
@ 2015-05-03  3:59     ` Kenneth Westfield
  2015-05-05  7:17     ` Srinivas Kandagatla
  1 sibling, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-03  3:59 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Sat, May 02, 2015 at 05:03:07PM -0700, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:18:26PM +0100, Srinivas Kandagatla wrote:
> > This patch adds bindings for apq8016 machine driver.
> > On APQ8016 4 MI2S can be configured to different sinks like internal
> > codec/external codec, this connection is controlled via 2 iomux
> > registers.
> > 
> > +sound: sound {
> > +	compatible = "qcom,apq8016-sndcard";
> > +	reg = <0x07702000 0x4>, <0x07702004 0x4>;
> > +	reg-names = "mic-iomux", "spkr-iomux";
> > +	qcom,model = "DB410c";
> > +
> > +	/* I2S - Internal codec */
> > +	internal-dai-link@0 {
> > +		cpu { /* PRIMARY */
> > +			sound-dai = <&lpass MI2S_PRIMARY>;
> > +		};
> > +		codec {
> > +			sound-dai = <&wcd_codec 0>;
> > +		};
> > +	};
> > +
> > +	/* External Primary or External Secondary -ADV7533 HDMI */
> > +	external-dai-link@0 {
> > +		external;
> > +		cpu { /* QUAT */
> > +			sound-dai = <&lpass MI2S_QUATERNARY>;
> > +		};
> > +		codec {
> > +			sound-dai = <&adv_bridge 0>;
> > +		};
> > +	};
> > +};
> 
> OK, although I will need to double-check this with the spec, it seems
> (from the patches) that there are 4 I2S ports, 2 of which are being
> used.  Usually, multi-channel audio is sent to the primary dai (which
> is MI2S), which then gets sent to the other ports by HW.  If that holds
> true for this SOC, then the external cpu dai should be labelled I2S,
> not MI2S.  If not, then both should be labelled as I2S (and the DAI
> channel constraints should be reduced to 1-2).
> 
> Looking at patch 12, the internal DAI is labelled Headset and the
> external DAI is labelled HDMI.  I will check the spec to see if the QUAT
> I2S port can handle multi-channel.

Are you planning on supporting multi-channel audio playback on HDMI, or
just stereo/mono?

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check.
  2015-04-30 17:16 ` [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check Srinivas Kandagatla
@ 2015-05-04 12:24   ` Mark Brown
  0 siblings, 0 replies; 88+ messages in thread
From: Mark Brown @ 2015-05-04 12:24 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 186 bytes --]

On Thu, Apr 30, 2015 at 06:16:35PM +0100, Srinivas Kandagatla wrote:
> This patch remove redundant check after request_resource as ioremap would
> do the check anyway.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 02/14] ASoC: qcom: remove unnecessary header files
  2015-04-30 17:16 ` [RFC PATCH 02/14] ASoC: qcom: remove unnecessary header files Srinivas Kandagatla
@ 2015-05-04 12:24   ` Mark Brown
  0 siblings, 0 replies; 88+ messages in thread
From: Mark Brown @ 2015-05-04 12:24 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 167 bytes --]

On Thu, Apr 30, 2015 at 06:16:44PM +0100, Srinivas Kandagatla wrote:
> This patch removes unnecessary header files in lpass cpu and platform
> code.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant
  2015-04-30 17:17 ` [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant Srinivas Kandagatla
  2015-05-02 23:58   ` Kenneth Westfield
@ 2015-05-04 12:26   ` Mark Brown
  2015-05-05  7:16     ` Srinivas Kandagatla
  1 sibling, 1 reply; 88+ messages in thread
From: Mark Brown @ 2015-05-04 12:26 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 315 bytes --]

On Thu, Apr 30, 2015 at 06:17:24PM +0100, Srinivas Kandagatla wrote:

> +	if (!drvdata->variant->no_osr_clk) {
> +		ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->id]);

Can we do this by checking to see if the clock is set to IS_ERR()
instead?  That's what we're doing elsewhere for possibly optional
clocks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-02 23:57   ` Kenneth Westfield
@ 2015-05-05  5:19     ` Kenneth Westfield
  2015-05-05  7:17       ` Srinivas Kandagatla
  2015-05-05  7:16     ` Srinivas Kandagatla
  1 sibling, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-05  5:19 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Sat, May 02, 2015 at 04:57:38PM -0700, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:16:53PM +0100, Srinivas Kandagatla wrote:
> > This patch tries to make the lpass driver more generic by moving the
> > ipq806x specific bits out of the cpu and platform driver, also allows
> the
> > SOC specific drivers to add the correct register offsets.
> > 
> > This patch also renames the register definition header file into more
> > generic header file.
> 
> > diff --git a/sound/soc/qcom/lpass-ipq806x.c
> b/sound/soc/qcom/lpass-ipq806x.c
> > new file mode 100644
> > index 0000000..8e9a427
> > --- /dev/null
> > +++ b/sound/soc/qcom/lpass-ipq806x.c

> > +enum lpaif_i2s_ports {
> > +	LPAIF_I2S_PORT_MIN		= 0,
> > +
> > +	LPAIF_I2S_PORT_CODEC_SPK	= 0,
> > +	LPAIF_I2S_PORT_CODEC_MIC	= 1,
> > +	LPAIF_I2S_PORT_SEC_SPK		= 2,
> > +	LPAIF_I2S_PORT_SEC_MIC		= 3,
> > +	LPAIF_I2S_PORT_MI2S		= 4,
> > +
> > +	LPAIF_I2S_PORT_MAX		= 4,
> > +	LPAIF_I2S_PORT_NUM		= 5,
> > +};
> 
> These port mappings here...
> 
> > +enum lpaif_irq_ports {
> > +	LPAIF_IRQ_PORT_MIN		= 0,
> > +
> > +	LPAIF_IRQ_PORT_HOST		= 0,
> > +	LPAIF_IRQ_PORT_ADSP		= 1,
> > +
> > +	LPAIF_IRQ_PORT_MAX		= 2,
> > +	LPAIF_IRQ_PORT_NUM		= 3,
> > +};
> 
> ...here...
> 
> > +enum lpaif_dma_channels {
> > +	LPAIF_RDMA_CHAN_MIN		= 0,
> > +
> > +	LPAIF_RDMA_CHAN_MI2S		= 0,
> > +	LPAIF_RDMA_CHAN_PCM0		= 1,
> > +	LPAIF_RDMA_CHAN_PCM1		= 2,
> > +
> > +	LPAIF_RDMA_CHAN_MAX		= 4,
> > +	LPAIF_RDMA_CHAN_NUM		= 5,
> > +};
> 
> ...and here can be SOC-specific.  Should move them to the SOC-specific
> files.

Expanding on this, the I2S port mappings for the APQ8016 should replace
the ones defined above with the constants you refer to in
dt-bindings/sound/apq8016.h:
   MI2S_PRIMARY
   MI2S_SECONDARY
   etc.

Maybe defining a corresponding ipq806x.h in the same directory, and
moving the above definitions there?

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-02 23:57   ` Kenneth Westfield
  2015-05-05  5:19     ` Kenneth Westfield
@ 2015-05-05  7:16     ` Srinivas Kandagatla
  2015-05-06  5:35       ` [alsa-devel] " Kenneth Westfield
  1 sibling, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:16 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 03/05/15 00:57, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:16:53PM +0100, Srinivas Kandagatla wrote:
>> This patch tries to make the lpass driver more generic by moving the
>> ipq806x specific bits out of the cpu and platform driver, also allows the
>> SOC specific drivers to add the correct register offsets.
>>
>> This patch also renames the register definition header file into more
>> generic header file.
>
>> diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
>> new file mode 100644
>> index 0000000..8e9a427
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-ipq806x.c
>
>> +static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
>> +	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
>> +	{}
>> +};
>> +MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
>
> Surround with #ifdef CONFIG_OF?

I was more of thinking adding "depends OF" in Kconfig.
Is there any possibility that the driver would support non-DT?

>
>> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
>> new file mode 100644
>> index 0000000..5541b14
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
>
>> +#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
>> +	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
>
> Could all of these variant-related macros be eliminated by using the
> regmap_fields_* accessor functions, instead of the regmap_* functions?
Possible, I will give it a try.

>
>> +enum lpaif_i2s_ports {
>> +	LPAIF_I2S_PORT_MIN		= 0,
>> +
>> +	LPAIF_I2S_PORT_CODEC_SPK	= 0,
>> +	LPAIF_I2S_PORT_CODEC_MIC	= 1,
>> +	LPAIF_I2S_PORT_SEC_SPK		= 2,
>> +	LPAIF_I2S_PORT_SEC_MIC		= 3,
>> +	LPAIF_I2S_PORT_MI2S		= 4,
>> +
>> +	LPAIF_I2S_PORT_MAX		= 4,
>> +	LPAIF_I2S_PORT_NUM		= 5,
>> +};
>
> These port mappings here...
>
>> +enum lpaif_irq_ports {
>> +	LPAIF_IRQ_PORT_MIN		= 0,
>> +
>> +	LPAIF_IRQ_PORT_HOST		= 0,
>> +	LPAIF_IRQ_PORT_ADSP		= 1,
>> +
>> +	LPAIF_IRQ_PORT_MAX		= 2,
>> +	LPAIF_IRQ_PORT_NUM		= 3,
>> +};
>
> ...here...
>
>> +enum lpaif_dma_channels {
>> +	LPAIF_RDMA_CHAN_MIN		= 0,
>> +
>> +	LPAIF_RDMA_CHAN_MI2S		= 0,
>> +	LPAIF_RDMA_CHAN_PCM0		= 1,
>> +	LPAIF_RDMA_CHAN_PCM1		= 2,
>> +
>> +	LPAIF_RDMA_CHAN_MAX		= 4,
>> +	LPAIF_RDMA_CHAN_NUM		= 5,
>> +};
>
> ...and here can be SOC-specific.  Should move them to the SOC-specific
> files.
Yes, I agree, i will move them to soc specific header file.

>
>> diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
>> index 5c99b3d..5bd2a90 100644
>> --- a/sound/soc/qcom/lpass.h
>> +++ b/sound/soc/qcom/lpass.h
>
>>   /* register the platform driver from the CPU DAI driver */
>>   int asoc_qcom_lpass_platform_register(struct platform_device *);
>> +int lpass_cpu_platform_remove(struct platform_device *pdev);
>> +int lpass_cpu_platform_probe(struct platform_device *pdev);
>> +int lpass_cpu_dai_probe(struct snd_soc_dai *dai);
>> +extern struct snd_soc_dai_ops lpass_cpu_dai_ops;
>
> Prefix with asoc_qcom_ to reduce chance of collisions.
>
Sounds sensible, Will fix it in next version.

--srini

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant
  2015-05-04 12:26   ` Mark Brown
@ 2015-05-05  7:16     ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:16 UTC (permalink / raw)
  To: Mark Brown
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm



On 04/05/15 13:26, Mark Brown wrote:
> On Thu, Apr 30, 2015 at 06:17:24PM +0100, Srinivas Kandagatla wrote:
>
>> +	if (!drvdata->variant->no_osr_clk) {
>> +		ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->id]);
>
> Can we do this by checking to see if the clock is set to IS_ERR()
> instead?  That's what we're doing elsewhere for possibly optional
> clocks.
>
Yes, I think that should be possible, I will fix it in next version.

--srini

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data
  2015-05-02 23:59   ` Kenneth Westfield
@ 2015-05-05  7:16     ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:16 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 03/05/15 00:59, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:17:32PM +0100, Srinivas Kandagatla wrote:
>> This patch adds ability to pass dma channel control bits start offset, which
>> differ in differnet qcom SOCs. On apq8016 dma channel control bits start
>> after an offset of 1.
>
> Alot of the SOCs have similar small differences in the LPASS register
> map.  For now, this is fine, but we will probably want to add some
> system of quirks to handle these differences; as more SOCs drivers
> are implemented.
>
Yes, I agree, only reason for adding it in to variant data could be that 
I was looking at drivers/mmc/host/mmmci.c file a lot :-)

--srini

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings
  2015-05-03  0:03   ` Kenneth Westfield
  2015-05-03  3:59     ` Kenneth Westfield
@ 2015-05-05  7:17     ` Srinivas Kandagatla
  2015-05-06  5:41       ` [alsa-devel] " Kenneth Westfield
  1 sibling, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 03/05/15 01:03, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:18:26PM +0100, Srinivas Kandagatla wrote:
>> This patch adds bindings for apq8016 machine driver.
>> On APQ8016 4 MI2S can be configured to different sinks like internal
>> codec/external codec, this connection is controlled via 2 iomux
>> registers.
>>
>> +sound: sound {
>> +	compatible = "qcom,apq8016-sndcard";
>> +	reg = <0x07702000 0x4>, <0x07702004 0x4>;
>> +	reg-names = "mic-iomux", "spkr-iomux";
>> +	qcom,model = "DB410c";
>> +
>> +	/* I2S - Internal codec */
>> +	internal-dai-link@0 {
>> +		cpu { /* PRIMARY */
>> +			sound-dai = <&lpass MI2S_PRIMARY>;
>> +		};
>> +		codec {
>> +			sound-dai = <&wcd_codec 0>;
>> +		};
>> +	};
>> +
>> +	/* External Primary or External Secondary -ADV7533 HDMI */
>> +	external-dai-link@0 {
>> +		external;
>> +		cpu { /* QUAT */
>> +			sound-dai = <&lpass MI2S_QUATERNARY>;
>> +		};
>> +		codec {
>> +			sound-dai = <&adv_bridge 0>;
>> +		};
>> +	};
>> +};
>
> OK, although I will need to double-check this with the spec, it seems
> (from the patches) that there are 4 I2S ports, 2 of which are being
> used.  Usually, multi-channel audio is sent to the primary dai (which
> is MI2S), which then gets sent to the other ports by HW.  If that holds
> true for this SOC, then the external cpu dai should be labelled I2S,
> not MI2S.  If not, then both should be labelled as I2S (and the DAI
> channel constraints should be reduced to 1-2).
>
I have got very limited access to documentation, which obviously does 
not have any info related to channel capabilities. I was thinking that 
all the playback ports support multi-channel. I might be wrong though.

> Looking at patch 12, the internal DAI is labelled Headset and the
> external DAI is labelled HDMI.
This naming is very specific to the SBC board.

   I will check the spec to see if the QUAT
> I2S port can handle multi-channel.
External HDMI bridge on the other side only supports 2-channels, but if 
you can re-check on the channel capabilities would be good.

--srini

>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel
  2015-05-03  0:00   ` Kenneth Westfield
@ 2015-05-05  7:17     ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 03/05/15 01:00, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:17:42PM +0100, Srinivas Kandagatla wrote:
>> This patch adds ablity to lpass driver to handle interrupt per dma
>> channel. Without this patch its not possible to use multipl ports on the
>> lpass.
>
>> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
>> index 8ab0ac1..c5907d5 100644
>> --- a/sound/soc/qcom/lpass-platform.c
>> +++ b/sound/soc/qcom/lpass-platform.c
>
>> -static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
>> +static irqreturn_t lpass_dma_interrupt_handler(
>> +			struct snd_pcm_substream *substream,
>> +			struct lpass_data *drvdata,
>> +			int chan, u32 interrupts)
>>   {
>> -	struct snd_pcm_substream *substream = data;
>>   	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
>> -	struct lpass_data *drvdata =
>> -		snd_soc_platform_get_drvdata(soc_runtime->platform);
>>   	struct lpass_variant *v = drvdata->variant;
>> -	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
>> -	unsigned int interrupts;
>>   	irqreturn_t ret = IRQ_NONE;
>> -	int rv, chan = pcm_data->rdma_ch;
>> -
>> -	rv = regmap_read(drvdata->lpaif_map,
>> -			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
>> -	if (rv) {
>> -		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
>> -				__func__, rv);
>> -		return IRQ_NONE;
>> -	}
>> -
>> -	interrupts &= LPAIF_IRQ_ALL(chan);
>> +	int rv;
>>
>>   	if (interrupts & LPAIF_IRQ_PER(chan)) {
>>   		rv = regmap_write(drvdata->lpaif_map,
>> @@ -422,6 +410,30 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
>>   	return ret;
>
> You are returning the ISR result here...
>
>>   }
>>
>> +static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
>> +{
>> +	struct lpass_data *drvdata = data;
>> +	struct lpass_variant *v = drvdata->variant;
>> +	unsigned int irqs;
>> +	int rv, chan;
>> +
>> +	rv = regmap_read(drvdata->lpaif_map,
>> +			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
>> +	if (rv) {
>> +		pr_err("%s() error reading from irqstat reg: %d\n",
>> +				__func__, rv);
>> +		return IRQ_NONE;
>> +	}
>> +
>> +	/* Handle per channel interrupts */
>> +	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++)
>> +		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan])
>> +			lpass_dma_interrupt_handler(drvdata->substream[chan],
>> +						    drvdata, chan, irqs);
>
> ...but ignoring the result here and always returning HANDLED.
>
That's correct, I will fix this in next version.

>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>
>>   int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>>   {
>>   	struct lpass_data *drvdata = platform_get_drvdata(pdev);
>> +	struct lpass_variant *v = drvdata->variant;
>> +	int ret;
>>
>>   	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
>>   	if (drvdata->lpaif_irq < 0) {
>> @@ -553,6 +553,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
>>   		return -ENODEV;
>>   	}
>>
>> +	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
>> +			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
>> +			"lpass-irq-lpaif", drvdata);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "%s() irq request failed: %d\n",
>> +				__func__, ret);
>> +		return ret;
>> +	}
>> +
>> +	/* ensure audio hardware is disabled */
>> +	ret = regmap_write(drvdata->lpaif_map,
>> +			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
>> +				__func__, ret);
>> +		return ret;
>> +	}
>
> Looking at this, it may be safer to disable the interrupt sources before
> getting/enabling the interrupt, i.e. do the regmap_write first, then
> devm_request_irq.
Yes, Its not safe, will fix it in next version too.

--srini
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-05  5:19     ` Kenneth Westfield
@ 2015-05-05  7:17       ` Srinivas Kandagatla
  2015-05-06  5:43         ` [alsa-devel] " Kenneth Westfield
  0 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 05/05/15 06:19, Kenneth Westfield wrote:
>>> > >+enum lpaif_i2s_ports {
>>> > >+	LPAIF_I2S_PORT_MIN		= 0,
>>> > >+
>>> > >+	LPAIF_I2S_PORT_CODEC_SPK	= 0,
>>> > >+	LPAIF_I2S_PORT_CODEC_MIC	= 1,
>>> > >+	LPAIF_I2S_PORT_SEC_SPK		= 2,
>>> > >+	LPAIF_I2S_PORT_SEC_MIC		= 3,
>>> > >+	LPAIF_I2S_PORT_MI2S		= 4,
>>> > >+
>>> > >+	LPAIF_I2S_PORT_MAX		= 4,
>>> > >+	LPAIF_I2S_PORT_NUM		= 5,
>>> > >+};
>> >
>> >These port mappings here...
>> >
>>> > >+enum lpaif_irq_ports {
>>> > >+	LPAIF_IRQ_PORT_MIN		= 0,
>>> > >+
>>> > >+	LPAIF_IRQ_PORT_HOST		= 0,
>>> > >+	LPAIF_IRQ_PORT_ADSP		= 1,
>>> > >+
>>> > >+	LPAIF_IRQ_PORT_MAX		= 2,
>>> > >+	LPAIF_IRQ_PORT_NUM		= 3,
>>> > >+};
>> >
>> >...here...
>> >
>>> > >+enum lpaif_dma_channels {
>>> > >+	LPAIF_RDMA_CHAN_MIN		= 0,
>>> > >+
>>> > >+	LPAIF_RDMA_CHAN_MI2S		= 0,
>>> > >+	LPAIF_RDMA_CHAN_PCM0		= 1,
>>> > >+	LPAIF_RDMA_CHAN_PCM1		= 2,
>>> > >+
>>> > >+	LPAIF_RDMA_CHAN_MAX		= 4,
>>> > >+	LPAIF_RDMA_CHAN_NUM		= 5,
>>> > >+};
>> >
>> >...and here can be SOC-specific.  Should move them to the SOC-specific
>> >files.
> Expanding on this, the I2S port mappings for the APQ8016 should replace
> the ones defined above with the constants you refer to in
> dt-bindings/sound/apq8016.h:
>     MI2S_PRIMARY
>     MI2S_SECONDARY
>     etc.
>
> Maybe defining a corresponding ipq806x.h in the same directory, and
> moving the above definitions there?

As you pointed out i2s ports definitions can be moved to 
dt-bindings/soc/ipq806x.h but the channels can be directly defined in 
lpass-ipq806x.c as there would be no DT consumers for these defines anyway.

--srini

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant
  2015-05-02 23:58   ` Kenneth Westfield
@ 2015-05-05  7:17     ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 03/05/15 00:58, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:17:24PM +0100, Srinivas Kandagatla wrote:
>> Some LPASS integrations like on APQ8016 do not have OSR clk, so adding
>> no osr clk bit would allow such integrations to use lpass driver.
>
> Going forward, as the code is generalized, perhaps having an enable flag
> for each clock, rather than a flag that negates an existing clock?
> Or checking that the clock pointer is NULL after probing would be the
> indication?
Mark also suggested the same thing, I will fix it in next version.

--srini

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support
  2015-05-03  0:01   ` Kenneth Westfield
@ 2015-05-05  7:17     ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-05  7:17 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm


On 03/05/15 01:01, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:18:07PM +0100, Srinivas Kandagatla wrote:
>> This patch adds apq8016 machine driver support. This patch was tested on
>> two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
>> features.
>
> apq8016 refers to the SOC, whereas machine drivers are board-specific.
> Better to reference the board (or SOC-Codec combo) instead.

Yes, Initially I started of with apq8016-sbc, but as it also worked for 
mtp, I had to rename it to apq8016.

But you are right, I think renaming it to apq8016-sbc.c and 
msm8916-mtp.c would make sense.


--srini
>
>> ---
>>   sound/soc/qcom/Kconfig   |   9 ++
>>   sound/soc/qcom/Makefile  |   1 +
>>   sound/soc/qcom/apq8016.c | 214 +++++++++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 224 insertions(+)
>>   create mode 100644 sound/soc/qcom/apq8016.c
>
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-05  7:16     ` Srinivas Kandagatla
@ 2015-05-06  5:35       ` Kenneth Westfield
  0 siblings, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-06  5:35 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

On Tue, May 05, 2015 at 12:16:46AM -0700, Srinivas Kandagatla wrote:
> On 03/05/15 00:57, Kenneth Westfield wrote:
> >On Thu, Apr 30, 2015 at 06:16:53PM +0100, Srinivas Kandagatla wrote:
> >>This patch tries to make the lpass driver more generic by moving the
> >>ipq806x specific bits out of the cpu and platform driver, also allows
> the
> >>SOC specific drivers to add the correct register offsets.
> >>
> >>This patch also renames the register definition header file into more
> >>generic header file.
> >
> >>diff --git a/sound/soc/qcom/lpass-ipq806x.c
> b/sound/soc/qcom/lpass-ipq806x.c
> >>new file mode 100644
> >>index 0000000..8e9a427
> >>--- /dev/null
> >>+++ b/sound/soc/qcom/lpass-ipq806x.c
> >
> >>+static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
> >>+	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
> >>+	{}
> >>+};
> >>+MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
> >
> >Surround with #ifdef CONFIG_OF?
> 
> I was more of thinking adding "depends OF" in Kconfig.

Works for me.

> Is there any possibility that the driver would support non-DT?

Not that I am aware of.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings
  2015-05-05  7:17     ` Srinivas Kandagatla
@ 2015-05-06  5:41       ` Kenneth Westfield
  0 siblings, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-06  5:41 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

On Tue, May 05, 2015 at 12:17:01AM -0700, Srinivas Kandagatla wrote:
> On 03/05/15 01:03, Kenneth Westfield wrote:
> >On Thu, Apr 30, 2015 at 06:18:26PM +0100, Srinivas Kandagatla wrote:
> >>This patch adds bindings for apq8016 machine driver.
> >>On APQ8016 4 MI2S can be configured to different sinks like internal
> >>codec/external codec, this connection is controlled via 2 iomux
> >>registers.
> >>
> >>+sound: sound {
> >>+	compatible = "qcom,apq8016-sndcard";
> >>+	reg = <0x07702000 0x4>, <0x07702004 0x4>;
> >>+	reg-names = "mic-iomux", "spkr-iomux";
> >>+	qcom,model = "DB410c";
> >>+
> >>+	/* I2S - Internal codec */
> >>+	internal-dai-link@0 {
> >>+		cpu { /* PRIMARY */
> >>+			sound-dai = <&lpass MI2S_PRIMARY>;
> >>+		};
> >>+		codec {
> >>+			sound-dai = <&wcd_codec 0>;
> >>+		};
> >>+	};
> >>+
> >>+	/* External Primary or External Secondary -ADV7533 HDMI */
> >>+	external-dai-link@0 {
> >>+		external;
> >>+		cpu { /* QUAT */
> >>+			sound-dai = <&lpass MI2S_QUATERNARY>;
> >>+		};
> >>+		codec {
> >>+			sound-dai = <&adv_bridge 0>;
> >>+		};
> >>+	};
> >>+};
> >
> >OK, although I will need to double-check this with the spec, it seems
> >(from the patches) that there are 4 I2S ports, 2 of which are being
> >used.  Usually, multi-channel audio is sent to the primary dai (which
> >is MI2S), which then gets sent to the other ports by HW.  If that holds
> >true for this SOC, then the external cpu dai should be labelled I2S,
> >not MI2S.  If not, then both should be labelled as I2S (and the DAI
> >channel constraints should be reduced to 1-2).
> >
> I have got very limited access to documentation, which obviously
> does not have any info related to channel capabilities. I was
> thinking that all the playback ports support multi-channel. I might
> be wrong though.

After checking the specs, the four playback DAIs are, in fact,
multi-channel.  Therefore, MI2S_ is the correct prefix for them.

> 
> >Looking at patch 12, the internal DAI is labelled Headset and the
> >external DAI is labelled HDMI.
> This naming is very specific to the SBC board.
> 
>   I will check the spec to see if the QUAT
> >I2S port can handle multi-channel.
> External HDMI bridge on the other side only supports 2-channels, but
> if you can re-check on the channel capabilities would be good.

Ah, ok.  Then no need to worry about multi-channel playback.  Just need
to ensure the codec drivers constrain the channels to mono/stereo.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-05  7:17       ` Srinivas Kandagatla
@ 2015-05-06  5:43         ` Kenneth Westfield
  0 siblings, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-06  5:43 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

On Tue, May 05, 2015 at 12:17:23AM -0700, Srinivas Kandagatla wrote:
> On 05/05/15 06:19, Kenneth Westfield wrote:
> >>>> >+enum lpaif_i2s_ports {
> >>>> >+	LPAIF_I2S_PORT_MIN		= 0,
> >>>> >+
> >>>> >+	LPAIF_I2S_PORT_CODEC_SPK	= 0,
> >>>> >+	LPAIF_I2S_PORT_CODEC_MIC	= 1,
> >>>> >+	LPAIF_I2S_PORT_SEC_SPK		= 2,
> >>>> >+	LPAIF_I2S_PORT_SEC_MIC		= 3,
> >>>> >+	LPAIF_I2S_PORT_MI2S		= 4,
> >>>> >+
> >>>> >+	LPAIF_I2S_PORT_MAX		= 4,
> >>>> >+	LPAIF_I2S_PORT_NUM		= 5,
> >>>> >+};
> >>>
> >>>These port mappings here...
> >>>
> >>>> >+enum lpaif_irq_ports {
> >>>> >+	LPAIF_IRQ_PORT_MIN		= 0,
> >>>> >+
> >>>> >+	LPAIF_IRQ_PORT_HOST		= 0,
> >>>> >+	LPAIF_IRQ_PORT_ADSP		= 1,
> >>>> >+
> >>>> >+	LPAIF_IRQ_PORT_MAX		= 2,
> >>>> >+	LPAIF_IRQ_PORT_NUM		= 3,
> >>>> >+};
> >>>
> >>>...here...
> >>>
> >>>> >+enum lpaif_dma_channels {
> >>>> >+	LPAIF_RDMA_CHAN_MIN		= 0,
> >>>> >+
> >>>> >+	LPAIF_RDMA_CHAN_MI2S		= 0,
> >>>> >+	LPAIF_RDMA_CHAN_PCM0		= 1,
> >>>> >+	LPAIF_RDMA_CHAN_PCM1		= 2,
> >>>> >+
> >>>> >+	LPAIF_RDMA_CHAN_MAX		= 4,
> >>>> >+	LPAIF_RDMA_CHAN_NUM		= 5,
> >>>> >+};
> >>>
> >>>...and here can be SOC-specific.  Should move them to the SOC-specific
> >>>files.
> >Expanding on this, the I2S port mappings for the APQ8016 should replace
> >the ones defined above with the constants you refer to in
> >dt-bindings/sound/apq8016.h:
> >    MI2S_PRIMARY
> >    MI2S_SECONDARY
> >    etc.
> >
> >Maybe defining a corresponding ipq806x.h in the same directory, and
> >moving the above definitions there?
> 
> As you pointed out i2s ports definitions can be moved to
> dt-bindings/soc/ipq806x.h but the channels can be directly defined
> in lpass-ipq806x.c as there would be no DT consumers for these
> defines
> anyway.

Moving the I2S ports to dt-bindings and the other definitions to their
SOC-specific source files works for me.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-02 23:57 ` [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
@ 2015-05-06  5:47   ` Kenneth Westfield
  2015-05-06  6:54     ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-06  5:47 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Sat, May 02, 2015 at 04:57:04PM -0700, Kenneth Westfield wrote:
> On Thu, Apr 30, 2015 at 06:15:48PM +0100, Srinivas Kandagatla wrote:
> > Hi All,
> > 
> > This patchset adds apq8016 audio support into lpass driver. Existing
> Lpass
> > driver can not be used as-it-is for apq8016 as it contains code specific
> to
> > ipq806x. Also the driver only supports single i2s port, single dma
> channel and
> > single bitclk control.
> > 
> > APQ8016 has 4 MI2S( Primary, Secondary, Tertiary, Quaternary) which can
> be routed
> > to internal wcd codec or external codecs. This routing is controlled by
> 2 mux
> > registers.
> > 
> > This patch series firstly re-organizes the lpass driver such that the
> SOC
> > specific bits are moved away from the driver. And secondly the SOC
> specifics
> > are now passed as lpass variant data which would include various
> register
> > offsets, dma channel allocations and SOC specific clock handling.
> > 
> > Finally the patchset add apq8016 lpass and machine driver.
> > 
> > This patchset also has two trivial cleanup patches which are to do with
> > redundant checks and removing unnecessary header files.
> > 
> > All these patches are tested for HDMI audio via adv7533 bridge and
> Analog audio
> > on APQ8016-SBC and msm8916-mtp boards. I dont have access to ipq806x
> boards to
> > test these patches.
> > 
> > This is very first version of the patches which was developed with very
> > mimimal/no access to IP documentation. I would like to get your opinon
> on the
> > over all approch.
> > 
> > 
> > Kenneth/Patrick,
> > 	Could you please try these patches on storm board?
> 
> I will test the patches and let you know by Wednesday.  Also, I posted
> some comments, but Patrick should be posting his comments separately
> later next week.

Srinivas,

After applying the patches, audio playback is no longer functional on
the storm board.  Give me some time to debug this and I will get back
to you.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-06  5:47   ` Kenneth Westfield
@ 2015-05-06  6:54     ` Srinivas Kandagatla
  2015-05-12  4:06       ` [alsa-devel] " Kenneth Westfield
  0 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-06  6:54 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

Hi Kenneth,

On 06/05/15 06:47, Kenneth Westfield wrote:
>> >
>> >I will test the patches and let you know by Wednesday.  Also, I posted
>> >some comments, but Patrick should be posting his comments separately
>> >later next week.
> Srinivas,
>
> After applying the patches, audio playback is no longer functional on
> the storm board.  Give me some time to debug this and I will get back
> to you.
I found atleast one issue with rdma audif bits in ipq806x lpass

could you try change, this will be fixed properly in next version.

-----------------------><---------------------------------------------
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 11a7053..2b00355 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -69,6 +69,7 @@ struct lpass_variant ipq806x_data = {
         .rdma_reg_base          = 0x6000,
         .rdma_reg_stride        = 0x1000,
         .rdma_channels          = 4,
+       .rdmactl_audif_start    = 4,
         .dai_driver             = &lpass_cpu_dai_driver,
         .num_dai                = 1,

-----------------------><---------------------------------------------


--srini

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-06  6:54     ` Srinivas Kandagatla
@ 2015-05-12  4:06       ` Kenneth Westfield
  2015-05-12 10:21         ` Srinivas Kandagatla
  2015-05-12 13:11         ` Srinivas Kandagatla
  0 siblings, 2 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-12  4:06 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

On Tue, May 05, 2015 at 11:54:16PM -0700, Srinivas Kandagatla wrote:
> Hi Kenneth,
> 
> On 06/05/15 06:47, Kenneth Westfield wrote:
> >>>
> >>>I will test the patches and let you know by Wednesday.  Also, I posted
> >>>some comments, but Patrick should be posting his comments separately
> >>>later next week.
> >Srinivas,
> >
> >After applying the patches, audio playback is no longer functional on
> >the storm board.  Give me some time to debug this and I will get back
> >to you.
> I found atleast one issue with rdma audif bits in ipq806x lpass
> 
> could you try change, this will be fixed properly in next version.
> 
> -----------------------><---------------------------------------------
> diff --git a/sound/soc/qcom/lpass-ipq806x.c
> b/sound/soc/qcom/lpass-ipq806x.c
> index 11a7053..2b00355 100644
> --- a/sound/soc/qcom/lpass-ipq806x.c
> +++ b/sound/soc/qcom/lpass-ipq806x.c
> @@ -69,6 +69,7 @@ struct lpass_variant ipq806x_data = {
>         .rdma_reg_base          = 0x6000,
>         .rdma_reg_stride        = 0x1000,
>         .rdma_channels          = 4,
> +       .rdmactl_audif_start    = 4,
>         .dai_driver             = &lpass_cpu_dai_driver,
>         .num_dai                = 1,
> 
> -----------------------><---------------------------------------------

Srinivas,

I was able to get audio working on the Storm board.  There were several
issues.  First, the I2S control port was saved in the DAI driver id field
(which was 4), but the DAI id field was used by the macro (which was 0).
The patch below fixed it:

-----------------------><---------------------------------------------
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 17ad20d..58ae8af 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -146,7 +146,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -171,7 +171,7 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -186,7 +186,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -206,7 +206,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
+				LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -217,7 +217,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
+				LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -247,7 +247,7 @@ int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
-----------------------><---------------------------------------------

In addition to your patch above, I also needed to correct the rdma_port
assignment by removing the i2s port reference:

-----------------------><---------------------------------------------
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index c5907d5..580cae1 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
+	int ret, rdma_port = v->rdmactl_audif_start;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
-----------------------><---------------------------------------------

Please incorporate these fixes into your next patch series.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-12  4:06       ` [alsa-devel] " Kenneth Westfield
@ 2015-05-12 10:21         ` Srinivas Kandagatla
  2015-05-12 17:04           ` Lars-Peter Clausen
  2015-05-12 13:11         ` Srinivas Kandagatla
  1 sibling, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-12 10:21 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm, lars

+ adding Lars

On 12/05/15 05:06, Kenneth Westfield wrote:
> Srinivas,
>
> I was able to get audio working on the Storm board.  There were several
> issues.  First, the I2S control port was saved in the DAI driver id field
> (which was 4), but the DAI id field was used by the macro (which was 0).
> The patch below fixed it:

Ah, I did not expect that to happen, dai->id and dai->driver->id should 
be same. Surprisingly this is not true for IPQ806x platform only because 
dais count == 1. Which results in dai->id not getting assigned to 
dai->driver->id due to below code snippet in  sound/soc/soc-core.c

--------------------><------------------------------------------
/*
  * Back in the old days when we still had component-less DAIs,
  * instead of having a static name, component-less DAIs would
  * inherit the name of the parent device so it is possible to
  * register multiple instances of the DAI. We still need to keep
  * the same naming style even though those DAIs are not
  * component-less anymore.
  */
if (count == 1 && legacy_dai_naming) {
	dai->name = fmt_single_name(dev, &dai->id);
} else {
	dai->name = fmt_multiple_name(dev, &dai_drv[i]);
	if (dai_drv[i].id)
		dai->id = dai_drv[i].id;
	else
		dai->id = i;
}
--------------------><------------------------------------------

Its not clear from code, why should we enter to legacy naming if the 
dais count == 1 even-though the dai_drv has has valid name and id 
information.

Mark/Lars,

I can workaround this by using dai->driver->id in the driver, But do you 
think that dai name and id should be assigned from dai drv if present?

--srini

>
> -----------------------><---------------------------------------------
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 17ad20d..58ae8af 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -146,7 +146,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
>   	}
>
>   	ret = regmap_write(drvdata->lpaif_map,
> -			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   			   regval);
>   	if (ret) {
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
> @@ -171,7 +171,7 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
>   	int ret;
>
>   	ret = regmap_write(drvdata->lpaif_map,
> -			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
> +			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
>   	if (ret)
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
>   				__func__, ret);
> @@ -186,7 +186,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
>   	int ret;
>
>   	ret = regmap_update_bits(drvdata->lpaif_map,
> -			LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
>   	if (ret)
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
> @@ -206,7 +206,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_RESUME:
>   	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>   		ret = regmap_update_bits(drvdata->lpaif_map,
> -				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +				LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   				LPAIF_I2SCTL_SPKEN_MASK,
>   				LPAIF_I2SCTL_SPKEN_ENABLE);
>   		if (ret)
> @@ -217,7 +217,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_SUSPEND:
>   	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>   		ret = regmap_update_bits(drvdata->lpaif_map,
> -				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +				LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   				LPAIF_I2SCTL_SPKEN_MASK,
>   				LPAIF_I2SCTL_SPKEN_DISABLE);
>   		if (ret)
> @@ -247,7 +247,7 @@ int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
>
>   	/* ensure audio hardware is disabled */
>   	ret = regmap_write(drvdata->lpaif_map,
> -			LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
> +			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
>   	if (ret)
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
>   				__func__, ret);
> -----------------------><---------------------------------------------

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-12  4:06       ` [alsa-devel] " Kenneth Westfield
  2015-05-12 10:21         ` Srinivas Kandagatla
@ 2015-05-12 13:11         ` Srinivas Kandagatla
  1 sibling, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-12 13:11 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

Hi Kenneth,

On 12/05/15 05:06, Kenneth Westfield wrote:
> On Tue, May 05, 2015 at 11:54:16PM -0700, Srinivas Kandagatla wrote:
>> Hi Kenneth,
>>
>> On 06/05/15 06:47, Kenneth Westfield wrote:
>>>>>
>>>>> I will test the patches and let you know by Wednesday.  Also, I posted
>>>>> some comments, but Patrick should be posting his comments separately
>>>>> later next week.
>>> Srinivas,
>>>
>>> After applying the patches, audio playback is no longer functional on
>>> the storm board.  Give me some time to debug this and I will get back
>>> to you.
>> I found atleast one issue with rdma audif bits in ipq806x lpass
>>
>> could you try change, this will be fixed properly in next version.
>>
>> -----------------------><---------------------------------------------
>> diff --git a/sound/soc/qcom/lpass-ipq806x.c
>> b/sound/soc/qcom/lpass-ipq806x.c
>> index 11a7053..2b00355 100644
>> --- a/sound/soc/qcom/lpass-ipq806x.c
>> +++ b/sound/soc/qcom/lpass-ipq806x.c
>> @@ -69,6 +69,7 @@ struct lpass_variant ipq806x_data = {
>>          .rdma_reg_base          = 0x6000,
>>          .rdma_reg_stride        = 0x1000,
>>          .rdma_channels          = 4,
>> +       .rdmactl_audif_start    = 4,
>>          .dai_driver             = &lpass_cpu_dai_driver,
>>          .num_dai                = 1,
>>
>> -----------------------><---------------------------------------------
>
> Srinivas,
>
> I was able to get audio working on the Storm board.  There were several
> issues.  First, the I2S control port was saved in the DAI driver id field
> (which was 4), but the DAI id field was used by the macro (which was 0).
> The patch below fixed it:
>
> -----------------------><---------------------------------------------
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 17ad20d..58ae8af 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -146,7 +146,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
>   	}
>
>   	ret = regmap_write(drvdata->lpaif_map,
> -			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   			   regval);
>   	if (ret) {
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
> @@ -171,7 +171,7 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
>   	int ret;
>
>   	ret = regmap_write(drvdata->lpaif_map,
> -			   LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
> +			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
>   	if (ret)
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
>   				__func__, ret);
> @@ -186,7 +186,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
>   	int ret;
>
>   	ret = regmap_update_bits(drvdata->lpaif_map,
> -			LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
>   	if (ret)
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
> @@ -206,7 +206,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_RESUME:
>   	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>   		ret = regmap_update_bits(drvdata->lpaif_map,
> -				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +				LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   				LPAIF_I2SCTL_SPKEN_MASK,
>   				LPAIF_I2SCTL_SPKEN_ENABLE);
>   		if (ret)
> @@ -217,7 +217,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
>   	case SNDRV_PCM_TRIGGER_SUSPEND:
>   	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>   		ret = regmap_update_bits(drvdata->lpaif_map,
> -				LPAIF_I2SCTL_REG(drvdata->variant, dai->id),
> +				LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>   				LPAIF_I2SCTL_SPKEN_MASK,
>   				LPAIF_I2SCTL_SPKEN_DISABLE);
>   		if (ret)
> @@ -247,7 +247,7 @@ int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
>
>   	/* ensure audio hardware is disabled */
>   	ret = regmap_write(drvdata->lpaif_map,
> -			LPAIF_I2SCTL_REG(drvdata->variant, dai->id), 0);
> +			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
>   	if (ret)
>   		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
>   				__func__, ret);
> -----------------------><---------------------------------------------
>

> In addition to your patch above, I also needed to correct the rdma_port
> assignment by removing the i2s port reference:


>
> -----------------------><---------------------------------------------
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index c5907d5..580cae1 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
>   	unsigned int channels = params_channels(params);
>   	unsigned int regval;
>   	int bitwidth;
> -	int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
> +	int ret, rdma_port = v->rdmactl_audif_start;
>
>   	bitwidth = snd_pcm_format_width(format);
>   	if (bitwidth < 0) {
> -----------------------><---------------------------------------------
>
> Please incorporate these fixes into your next patch series.
>
I think my patch and above change for rdma port are not necessary as the 
rdma_port existing calculation would result 4 anyway, for 
rdmactl_audif_start= 0 and dai->driver->id = 4. Which is correct in MI2S 
case.

Only replacing dai->id to dai->driver->id should fix the issue on storm 
board. So I will drop these two changes in next verion.
--srini

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-12 10:21         ` Srinivas Kandagatla
@ 2015-05-12 17:04           ` Lars-Peter Clausen
  2015-05-14  7:55             ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Lars-Peter Clausen @ 2015-05-12 17:04 UTC (permalink / raw)
  To: Srinivas Kandagatla, Patrick Lai, Mark Brown, Rob Herring,
	Pawel Moll, Ian Campbell, Kumar Gala, Banajit Goswami,
	Liam Girdwood, Jaroslav Kysela, Takashi Iwai, devicetree,
	linux-kernel, alsa-devel, linux-arm-msm

On 05/12/2015 12:21 PM, Srinivas Kandagatla wrote:
> + adding Lars
>
> On 12/05/15 05:06, Kenneth Westfield wrote:
>> Srinivas,
>>
>> I was able to get audio working on the Storm board.  There were several
>> issues.  First, the I2S control port was saved in the DAI driver id field
>> (which was 4), but the DAI id field was used by the macro (which was 0).
>> The patch below fixed it:
>
> Ah, I did not expect that to happen, dai->id and dai->driver->id should be
> same. Surprisingly this is not true for IPQ806x platform only because dais
> count == 1. Which results in dai->id not getting assigned to dai->driver->id
> due to below code snippet in  sound/soc/soc-core.c
>
> --------------------><------------------------------------------
> /*
>   * Back in the old days when we still had component-less DAIs,
>   * instead of having a static name, component-less DAIs would
>   * inherit the name of the parent device so it is possible to
>   * register multiple instances of the DAI. We still need to keep
>   * the same naming style even though those DAIs are not
>   * component-less anymore.
>   */
> if (count == 1 && legacy_dai_naming) {
>      dai->name = fmt_single_name(dev, &dai->id);
> } else {
>      dai->name = fmt_multiple_name(dev, &dai_drv[i]);
>      if (dai_drv[i].id)
>          dai->id = dai_drv[i].id;
>      else
>          dai->id = i;
> }
> --------------------><------------------------------------------
>
> Its not clear from code, why should we enter to legacy naming if the dais
> count == 1 even-though the dai_drv has has valid name and id information.
>
> Mark/Lars,
>
> I can workaround this by using dai->driver->id in the driver, But do you
> think that dai name and id should be assigned from dai drv if present?

I think it should be OK to extend that if condition to

if (count == 1 && dai_drv[0].id == 0 && legacy_dai_naming) ...

It doesn't look like any of the systems for which we currently take the 
legacy path do set id to non 0. And the less new systems following legacy 
naming scheme the better.

- Lars


^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCH v1 00/13] ASoC: qcom: add support to apq8016 audio
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (14 preceding siblings ...)
  2015-05-02 23:57 ` [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
@ 2015-05-13 11:58 ` Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
                     ` (12 more replies)
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
  16 siblings, 13 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 11:58 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

Hi All,

Thankyou for reviewing the RFC patches, here is the v1 patchset after
incorporating review comments from RFC. This patchset adds apq8016 audio
support into lpass driver. Existing Lpass driver can not be used as-it-is for
apq8016 as it contains code specific to ipq806x. Also the driver only supports
single i2s port, single dma channel and single bitclk control.

APQ8016 has 4 MI2S( Primary, Secondary, Tertiary, Quaternary) which can be routed
to internal wcd codec or external codecs. This routing is controlled by 2 mux
registers.

This patch series firstly re-organizes the lpass driver such that the SOC
specific bits are moved away from the driver. And secondly the SOC specifics
are now passed as lpass variant data which would include various register
offsets, dma channel allocations and SOC specific clock handling.

Finally the patchset add apq8016 lpass and machine driver.

All these patches are tested for HDMI audio via adv7533 bridge and Analog audio
on APQ8016-SBC and msm8916-mtp boards. I dont have access to ipq806x boards to
test these patches.

Thanks Kenneth for testing the RFC patches on Storm board.

--srini

Changes since RFC(https://lwn.net/Articles/642661/)
 - droped cleanup patches, as they are already applied by Mark.
 - prefixed shared functions with asoc_qcom_* as suggested by Kenneth
 - made LPASS driver depended on OF.
 - removed ipq806x specific bits from ipaif_reg.h
 - removed no_osr clk flag as suggested by Mark and Kenneth
 - fixed irq return values spotted by Kenneth
 - renamed the machine file to apq8016-sbc.c as suggested by Kenneth.
 - use dai->driver->id instead of dai->id as it breaks on Storm board.

Srinivas Kandagatla (13):
  ASoC: qcom: make lpass driver depend on OF
  ASoC: qcom: move ipq806x specific bits out of lpass driver.
  ASoC: qcom: remove hardcoded i2s port number
  ASoC: qcom: remove hardcoded dma channel
  ASoC: qcom: support bitclk and osrclk per i2s port
  ASoC: qcom: make osr clock optional
  ASoC: qcom: add dma channel control offset to variant data
  ASoC: qcom: Add ability to handle interrupts per dma channel
  ASoC: qcom: add bit map to track static dma channel allocations
  ASoC: qcom: Add apq8016 lpass driver support
  ASoC: qcom: add apq8016 sound card support
  ASoC: qcom: Document apq8016 bindings.
  ASoC: qcom: document apq8016 sbc machine driver bindings

 .../devicetree/bindings/sound/qcom,apq8016-sbc.txt |  61 ++++++
 .../devicetree/bindings/sound/qcom,lpass-cpu.txt   |  13 +-
 include/dt-bindings/sound/apq8016-lpass.h          |   9 +
 sound/soc/qcom/Kconfig                             |  28 ++-
 sound/soc/qcom/Makefile                            |   6 +
 sound/soc/qcom/apq8016_sbc.c                       | 215 ++++++++++++++++++
 sound/soc/qcom/lpass-apq8016.c                     | 242 +++++++++++++++++++++
 sound/soc/qcom/lpass-cpu.c                         | 228 ++++++++++---------
 sound/soc/qcom/lpass-ipq806x.c                     | 109 ++++++++++
 sound/soc/qcom/lpass-lpaif-ipq806x.h               | 172 ---------------
 sound/soc/qcom/lpass-lpaif-reg.h                   | 126 +++++++++++
 sound/soc/qcom/lpass-platform.c                    | 196 +++++++++++------
 sound/soc/qcom/lpass.h                             |  51 ++++-
 13 files changed, 1109 insertions(+), 347 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
 create mode 100644 include/dt-bindings/sound/apq8016-lpass.h
 create mode 100644 sound/soc/qcom/apq8016_sbc.c
 create mode 100644 sound/soc/qcom/lpass-apq8016.c
 create mode 100644 sound/soc/qcom/lpass-ipq806x.c
 delete mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
 create mode 100644 sound/soc/qcom/lpass-lpaif-reg.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCH v1 01/13] ASoC: qcom: make lpass driver depend on OF
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
@ 2015-05-13 12:00   ` Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:00 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

lpass driver only support DT so make this explicit in the kconfig.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 5f58e4f..05b9840 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -6,12 +6,12 @@ config SND_SOC_QCOM
 
 config SND_SOC_LPASS_CPU
 	tristate
-	depends on SND_SOC_QCOM
+	depends on SND_SOC_QCOM && OF
 	select REGMAP_MMIO
 
 config SND_SOC_LPASS_PLATFORM
 	tristate
-	depends on SND_SOC_QCOM
+	depends on SND_SOC_QCOM && OF
 	select REGMAP_MMIO
 
 config SND_SOC_STORM
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
@ 2015-05-13 12:00   ` Srinivas Kandagatla
  2015-05-15  5:23     ` Kenneth Westfield
  2015-05-13 12:00   ` [PATCH v1 03/13] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
                     ` (10 subsequent siblings)
  12 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:00 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch tries to make the lpass driver more generic by moving the
ipq806x specific bits out of the cpu and platform driver, also allows the
SOC specific drivers to add the correct register offsets.

This patch also renames the register definition header file into more
generic header file.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig               |   9 +-
 sound/soc/qcom/Makefile              |   2 +
 sound/soc/qcom/lpass-cpu.c           | 157 ++++++++++++++++----------------
 sound/soc/qcom/lpass-ipq806x.c       |  96 +++++++++++++++++++
 sound/soc/qcom/lpass-lpaif-ipq806x.h | 172 -----------------------------------
 sound/soc/qcom/lpass-lpaif-reg.h     | 126 +++++++++++++++++++++++++
 sound/soc/qcom/lpass-platform.c      |  49 ++++++----
 sound/soc/qcom/lpass.h               |  28 ++++++
 8 files changed, 364 insertions(+), 275 deletions(-)
 create mode 100644 sound/soc/qcom/lpass-ipq806x.c
 delete mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
 create mode 100644 sound/soc/qcom/lpass-lpaif-reg.h

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 05b9840..865205e 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -14,11 +14,16 @@ config SND_SOC_LPASS_PLATFORM
 	depends on SND_SOC_QCOM && OF
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_IPQ806X
+	tristate
+	depends on SND_SOC_QCOM
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
-	select SND_SOC_LPASS_CPU
-	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_IPQ806X
 	select SND_SOC_MAX98357A
 	help
           Say Y or M if you want add support for SoC audio on the
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index c5ce96c..f8aab91 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,9 +1,11 @@
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
+snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
+obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 
 # Machine
 snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 4246970..2c20927 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -17,14 +17,14 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
-
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -138,7 +138,9 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S),
+			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -162,7 +164,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -177,7 +180,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+			LPAIF_I2SCTL_REG(drvdata->variant, LPAIF_I2S_PORT_MI2S),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -197,7 +200,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant,
+				LPAIF_I2S_PORT_MI2S),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -208,7 +212,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant,
+				LPAIF_I2S_PORT_MI2S),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -220,7 +225,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
+struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
 	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
 	.startup	= lpass_cpu_daiops_startup,
 	.shutdown	= lpass_cpu_daiops_shutdown,
@@ -229,41 +234,24 @@ static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
 	.prepare	= lpass_cpu_daiops_prepare,
 	.trigger	= lpass_cpu_daiops_trigger,
 };
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
 
-static int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
 
 	return ret;
 }
-
-static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
-	.playback = {
-		.stream_name	= "lpass-cpu-playback",
-		.formats	= SNDRV_PCM_FMTBIT_S16 |
-					SNDRV_PCM_FMTBIT_S24 |
-					SNDRV_PCM_FMTBIT_S32,
-		.rates		= SNDRV_PCM_RATE_8000 |
-					SNDRV_PCM_RATE_16000 |
-					SNDRV_PCM_RATE_32000 |
-					SNDRV_PCM_RATE_48000 |
-					SNDRV_PCM_RATE_96000,
-		.rate_min	= 8000,
-		.rate_max	= 96000,
-		.channels_min	= 1,
-		.channels_max	= 8,
-	},
-	.probe	= &lpass_cpu_dai_probe,
-	.ops    = &lpass_cpu_dai_ops,
-};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
 
 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 	.name = "lpass-cpu",
@@ -271,27 +259,29 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 
 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-		if (reg == LPAIF_I2SCTL_REG(i))
+	for (i = 0; i < v->i2s_ports; ++i)
+		if (reg == LPAIF_I2SCTL_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-		if (reg == LPAIF_IRQEN_REG(i))
+	for (i = 0; i < v->irq_ports; ++i) {
+		if (reg == LPAIF_IRQEN_REG(v, i))
 			return true;
-		if (reg == LPAIF_IRQCLEAR_REG(i))
+		if (reg == LPAIF_IRQCLEAR_REG(v, i))
 			return true;
 	}
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-		if (reg == LPAIF_RDMACTL_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_RDMACTL_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABASE_REG(i))
+		if (reg == LPAIF_RDMABASE_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABUFF_REG(i))
+		if (reg == LPAIF_RDMABUFF_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMAPER_REG(i))
+		if (reg == LPAIF_RDMAPER_REG(v, i))
 			return true;
 	}
 
@@ -300,29 +290,31 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-		if (reg == LPAIF_I2SCTL_REG(i))
+	for (i = 0; i < v->i2s_ports; ++i)
+		if (reg == LPAIF_I2SCTL_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-		if (reg == LPAIF_IRQEN_REG(i))
+	for (i = 0; i < v->irq_ports; ++i) {
+		if (reg == LPAIF_IRQEN_REG(v, i))
 			return true;
-		if (reg == LPAIF_IRQSTAT_REG(i))
+		if (reg == LPAIF_IRQSTAT_REG(v, i))
 			return true;
 	}
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-		if (reg == LPAIF_RDMACTL_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_RDMACTL_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABASE_REG(i))
+		if (reg == LPAIF_RDMABASE_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABUFF_REG(i))
+		if (reg == LPAIF_RDMABUFF_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMACURR_REG(i))
+		if (reg == LPAIF_RDMACURR_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMAPER_REG(i))
+		if (reg == LPAIF_RDMAPER_REG(v, i))
 			return true;
 	}
 
@@ -331,35 +323,39 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i)
-		if (reg == LPAIF_IRQSTAT_REG(i))
+	for (i = 0; i < v->irq_ports; ++i)
+		if (reg == LPAIF_IRQSTAT_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i)
-		if (reg == LPAIF_RDMACURR_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i)
+		if (reg == LPAIF_RDMACURR_REG(v, i))
 			return true;
 
 	return false;
 }
 
-static const struct regmap_config lpass_cpu_regmap_config = {
+static struct regmap_config lpass_cpu_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
-	.max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX),
 	.writeable_reg = lpass_cpu_regmap_writeable,
 	.readable_reg = lpass_cpu_regmap_readable,
 	.volatile_reg = lpass_cpu_regmap_volatile,
 	.cache_type = REGCACHE_FLAT,
 };
 
-static int lpass_cpu_platform_probe(struct platform_device *pdev)
+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata;
 	struct device_node *dsp_of_node;
 	struct resource *res;
+	struct lpass_variant *variant;
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *match;
 	int ret;
 
 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
@@ -375,6 +371,13 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drvdata);
 
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data)
+		return -EINVAL;
+
+	drvdata->variant = (struct lpass_variant *)match->data;
+	variant = drvdata->variant;
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
 
 	drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
@@ -385,6 +388,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return PTR_ERR((void const __force *)drvdata->lpaif);
 	}
 
+	lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
+						variant->rdma_channels);
+
 	drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
 			&lpass_cpu_regmap_config);
 	if (IS_ERR(drvdata->lpaif_map)) {
@@ -393,6 +399,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return PTR_ERR(drvdata->lpaif_map);
 	}
 
+	if (variant->init)
+		variant->init(pdev);
+
 	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
 	if (IS_ERR(drvdata->mi2s_osr_clk)) {
 		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
@@ -431,7 +440,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
-			&lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1);
+					      &lpass_cpu_comp_driver,
+					      variant->dai_driver,
+					      variant->num_dai);
 	if (ret) {
 		dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
 				__func__, ret);
@@ -451,33 +462,17 @@ err_clk:
 	clk_disable_unprepare(drvdata->ahbix_clk);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
 
-static int lpass_cpu_platform_remove(struct platform_device *pdev)
+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
 
+	if (drvdata->variant->exit)
+		drvdata->variant->exit(pdev);
+
 	clk_disable_unprepare(drvdata->ahbix_clk);
 
 	return 0;
 }
-
-#ifdef CONFIG_OF
-static const struct of_device_id lpass_cpu_device_id[] = {
-	{ .compatible = "qcom,lpass-cpu" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, lpass_cpu_device_id);
-#endif
-
-static struct platform_driver lpass_cpu_platform_driver = {
-	.driver	= {
-		.name		= "lpass-cpu",
-		.of_match_table	= of_match_ptr(lpass_cpu_device_id),
-	},
-	.probe	= lpass_cpu_platform_probe,
-	.remove	= lpass_cpu_platform_remove,
-};
-module_platform_driver(lpass_cpu_platform_driver);
-
-MODULE_DESCRIPTION("QTi LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
new file mode 100644
index 0000000..d1f698c
--- /dev/null
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ *
+ * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS
+ * Splited out the IPQ8064 soc specific from lpass-cpu.c
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+enum lpaif_i2s_ports {
+	IPQ806X_LPAIF_I2S_PORT_CODEC_SPK,
+	IPQ806X_LPAIF_I2S_PORT_CODEC_MIC,
+	IPQ806X_LPAIF_I2S_PORT_SEC_SPK,
+	IPQ806X_LPAIF_I2S_PORT_SEC_MIC,
+	IPQ806X_LPAIF_I2S_PORT_MI2S,
+};
+
+enum lpaif_dma_channels {
+	IPQ806X_LPAIF_RDMA_CHAN_MI2S,
+	IPQ806X_LPAIF_RDMA_CHAN_PCM0,
+	IPQ806X_LPAIF_RDMA_CHAN_PCM1,
+};
+
+static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
+	.playback = {
+		.stream_name	= "lpass-cpu-playback",
+		.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+		.rates		= SNDRV_PCM_RATE_8000 |
+					SNDRV_PCM_RATE_16000 |
+					SNDRV_PCM_RATE_32000 |
+					SNDRV_PCM_RATE_48000 |
+					SNDRV_PCM_RATE_96000,
+		.rate_min	= 8000,
+		.rate_max	= 96000,
+		.channels_min	= 1,
+		.channels_max	= 8,
+	},
+	.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+	.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+};
+
+struct lpass_variant ipq806x_data = {
+	.i2sctrl_reg_base	= 0x0010,
+	.i2sctrl_reg_stride	= 0x04,
+	.i2s_ports		= 5,
+	.irq_reg_base		= 0x3000,
+	.irq_reg_stride		= 0x1000,
+	.irq_ports		= 3,
+	.rdma_reg_base		= 0x6000,
+	.rdma_reg_stride	= 0x1000,
+	.rdma_channels		= 4,
+	.dai_driver		= &ipq806x_lpass_cpu_dai_driver,
+	.num_dai		= 1,
+};
+
+static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
+	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
+
+static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
+	.driver	= {
+		.name		= "lpass-cpu",
+		.of_match_table	= of_match_ptr(ipq806x_lpass_cpu_device_id),
+	},
+	.probe	= asoc_qcom_lpass_cpu_platform_probe,
+	.remove	= asoc_qcom_lpass_cpu_platform_remove,
+};
+module_platform_driver(ipq801x_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("QTi LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-ipq806x.h
deleted file mode 100644
index dc423b8..0000000
--- a/sound/soc/qcom/lpass-lpaif-ipq806x.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
- *
- * 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.
- *
- * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS
- */
-
-#ifndef __LPASS_LPAIF_H__
-#define __LPASS_LPAIF_H__
-
-#define LPAIF_BANK_OFFSET		0x1000
-
-/* LPAIF I2S */
-
-#define LPAIF_I2SCTL_REG_BASE		0x0010
-#define LPAIF_I2SCTL_REG_STRIDE		0x4
-#define LPAIF_I2SCTL_REG_ADDR(addr, port) \
-	(LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port)))
-
-enum lpaif_i2s_ports {
-	LPAIF_I2S_PORT_MIN		= 0,
-
-	LPAIF_I2S_PORT_CODEC_SPK	= 0,
-	LPAIF_I2S_PORT_CODEC_MIC	= 1,
-	LPAIF_I2S_PORT_SEC_SPK		= 2,
-	LPAIF_I2S_PORT_SEC_MIC		= 3,
-	LPAIF_I2S_PORT_MI2S		= 4,
-
-	LPAIF_I2S_PORT_MAX		= 4,
-	LPAIF_I2S_PORT_NUM		= 5,
-};
-
-#define LPAIF_I2SCTL_REG(port)		LPAIF_I2SCTL_REG_ADDR(0x0, (port))
-
-#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
-#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
-#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-
-#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
-#define LPAIF_I2SCTL_SPKEN_SHIFT	14
-#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
-#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
-#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
-#define LPAIF_I2SCTL_SPKMODE_NONE	(0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD0	(1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD1	(2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD2	(3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD3	(4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD01	(5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD23	(6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_6CH	(7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_8CH	(8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
-#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
-#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-
-#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
-#define LPAIF_I2SCTL_WSSRC_SHIFT	2
-#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
-#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
-
-#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
-#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
-#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-
-/* LPAIF IRQ */
-
-#define LPAIF_IRQ_REG_BASE		0x3000
-#define LPAIF_IRQ_REG_STRIDE		0x1000
-#define LPAIF_IRQ_REG_ADDR(addr, port) \
-	(LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port)))
-
-enum lpaif_irq_ports {
-	LPAIF_IRQ_PORT_MIN		= 0,
-
-	LPAIF_IRQ_PORT_HOST		= 0,
-	LPAIF_IRQ_PORT_ADSP		= 1,
-
-	LPAIF_IRQ_PORT_MAX		= 2,
-	LPAIF_IRQ_PORT_NUM		= 3,
-};
-
-#define LPAIF_IRQEN_REG(port)		LPAIF_IRQ_REG_ADDR(0x0, (port))
-#define LPAIF_IRQSTAT_REG(port)		LPAIF_IRQ_REG_ADDR(0x4, (port))
-#define LPAIF_IRQCLEAR_REG(port)	LPAIF_IRQ_REG_ADDR(0xC, (port))
-
-#define LPAIF_IRQ_BITSTRIDE		3
-#define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_XRUN(chan)		(2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-
-/* LPAIF DMA */
-
-#define LPAIF_RDMA_REG_BASE		0x6000
-#define LPAIF_RDMA_REG_STRIDE		0x1000
-#define LPAIF_RDMA_REG_ADDR(addr, chan) \
-	(LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan)))
-
-enum lpaif_dma_channels {
-	LPAIF_RDMA_CHAN_MIN		= 0,
-
-	LPAIF_RDMA_CHAN_MI2S		= 0,
-	LPAIF_RDMA_CHAN_PCM0		= 1,
-	LPAIF_RDMA_CHAN_PCM1		= 2,
-
-	LPAIF_RDMA_CHAN_MAX		= 4,
-	LPAIF_RDMA_CHAN_NUM		= 5,
-};
-
-#define LPAIF_RDMACTL_REG(chan)		LPAIF_RDMA_REG_ADDR(0x00, (chan))
-#define LPAIF_RDMABASE_REG(chan)	LPAIF_RDMA_REG_ADDR(0x04, (chan))
-#define	LPAIF_RDMABUFF_REG(chan)	LPAIF_RDMA_REG_ADDR(0x08, (chan))
-#define LPAIF_RDMACURR_REG(chan)	LPAIF_RDMA_REG_ADDR(0x0C, (chan))
-#define	LPAIF_RDMAPER_REG(chan)		LPAIF_RDMA_REG_ADDR(0x10, (chan))
-
-#define LPAIF_RDMACTL_BURSTEN_MASK	0x800
-#define LPAIF_RDMACTL_BURSTEN_SHIFT	11
-#define LPAIF_RDMACTL_BURSTEN_SINGLE	(0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-#define LPAIF_RDMACTL_BURSTEN_INCR4	(1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-
-#define LPAIF_RDMACTL_WPSCNT_MASK	0x700
-#define LPAIF_RDMACTL_WPSCNT_SHIFT	8
-#define LPAIF_RDMACTL_WPSCNT_ONE	(0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_TWO	(1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_THREE	(2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_FOUR	(3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_SIX	(5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_EIGHT	(7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-
-#define LPAIF_RDMACTL_AUDINTF_MASK	0x0F0
-#define LPAIF_RDMACTL_AUDINTF_SHIFT	4
-#define LPAIF_RDMACTL_AUDINTF_NONE	(0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_CODEC	(1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_PCM	(2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_I2S	(3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_MI2S	(4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_HDMI	(5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_PCM	(7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-
-#define LPAIF_RDMACTL_FIFOWM_MASK	0x00E
-#define LPAIF_RDMACTL_FIFOWM_SHIFT	1
-#define LPAIF_RDMACTL_FIFOWM_1		(0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_2		(1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_3		(2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_4		(3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_5		(4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_6		(5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_7		(6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_8		(7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-
-#define LPAIF_RDMACTL_ENABLE_MASK	0x1
-#define LPAIF_RDMACTL_ENABLE_SHIFT	0
-#define LPAIF_RDMACTL_ENABLE_OFF	(0 << LPAIF_RDMACTL_ENABLE_SHIFT)
-#define LPAIF_RDMACTL_ENABLE_ON		(1 << LPAIF_RDMACTL_ENABLE_SHIFT)
-
-#endif /* __LPASS_LPAIF_H__ */
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
new file mode 100644
index 0000000..95e22f1
--- /dev/null
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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 __LPASS_LPAIF_REG_H__
+#define __LPASS_LPAIF_REG_H__
+
+/* LPAIF I2S */
+
+#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
+	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
+
+#define LPAIF_I2SCTL_REG(v, port)	LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
+#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
+#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
+#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+
+#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
+#define LPAIF_I2SCTL_SPKEN_SHIFT	14
+#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
+#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
+#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
+#define LPAIF_I2SCTL_SPKMODE_NONE	(0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD0	(1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD1	(2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD2	(3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD3	(4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD01	(5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD23	(6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_6CH	(7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_8CH	(8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
+#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
+#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+
+#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
+#define LPAIF_I2SCTL_WSSRC_SHIFT	2
+#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
+#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
+
+#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
+#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
+#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+
+/* LPAIF IRQ */
+#define LPAIF_IRQ_REG_ADDR(v, addr, port) \
+	(v->irq_reg_base + (addr) + v->irq_reg_stride * (port))
+
+#define LPAIF_IRQ_PORT_HOST		0
+
+#define LPAIF_IRQEN_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x0, (port))
+#define LPAIF_IRQSTAT_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
+#define LPAIF_IRQCLEAR_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
+
+#define LPAIF_IRQ_BITSTRIDE		3
+
+#define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_XRUN(chan)		(2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+#define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+/* LPAIF DMA */
+
+#define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
+	(v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
+
+#define LPAIF_RDMACTL_AUDINTF(id)	(id << LPAIF_RDMACTL_AUDINTF_SHIFT)
+
+#define LPAIF_RDMACTL_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x00, (chan))
+#define LPAIF_RDMABASE_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x04, (chan))
+#define	LPAIF_RDMABUFF_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x08, (chan))
+#define LPAIF_RDMACURR_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x0C, (chan))
+#define	LPAIF_RDMAPER_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
+#define	LPAIF_RDMAPERCNT_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x14, (chan))
+
+#define LPAIF_RDMACTL_BURSTEN_MASK	0x800
+#define LPAIF_RDMACTL_BURSTEN_SHIFT	11
+#define LPAIF_RDMACTL_BURSTEN_SINGLE	(0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+#define LPAIF_RDMACTL_BURSTEN_INCR4	(1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+
+#define LPAIF_RDMACTL_WPSCNT_MASK	0x700
+#define LPAIF_RDMACTL_WPSCNT_SHIFT	8
+#define LPAIF_RDMACTL_WPSCNT_ONE	(0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_TWO	(1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_THREE	(2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_FOUR	(3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_SIX	(5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_EIGHT	(7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+
+#define LPAIF_RDMACTL_AUDINTF_MASK	0x0F0
+#define LPAIF_RDMACTL_AUDINTF_SHIFT	4
+
+#define LPAIF_RDMACTL_FIFOWM_MASK	0x00E
+#define LPAIF_RDMACTL_FIFOWM_SHIFT	1
+#define LPAIF_RDMACTL_FIFOWM_1		(0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_2		(1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_3		(2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_4		(3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_5		(4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_6		(5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_7		(6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_8		(7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+
+#define LPAIF_RDMACTL_ENABLE_MASK	0x1
+#define LPAIF_RDMACTL_ENABLE_SHIFT	0
+#define LPAIF_RDMACTL_ENABLE_OFF	(0 << LPAIF_RDMACTL_ENABLE_SHIFT)
+#define LPAIF_RDMACTL_ENABLE_ON		(1 << LPAIF_RDMACTL_ENABLE_SHIFT)
+
+#endif /* __LPASS_LPAIF_REG_H__ */
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index ffc0928..a38e7ec 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -21,7 +21,7 @@
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
@@ -80,6 +80,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	snd_pcm_format_t format = params_format(params);
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
@@ -150,7 +151,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), regval);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -165,10 +166,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -182,10 +184,11 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -194,7 +197,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABUFF_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -203,7 +206,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMAPER_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -212,7 +215,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -229,6 +232,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	switch (cmd) {
@@ -237,7 +241,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		/* clear status before enabling interrupts */
 		ret = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -246,7 +250,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
 		if (ret) {
@@ -256,7 +260,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_ON);
 		if (ret) {
@@ -269,7 +273,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_OFF);
 		if (ret) {
@@ -279,7 +283,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
@@ -298,11 +302,13 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
 	int ret;
 
 	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr);
+			 LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			 &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
 				__func__, ret);
@@ -310,7 +316,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	}
 
 	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr);
+			 LPAIF_RDMACURR_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			 &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
 				__func__, ret);
@@ -347,12 +354,13 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
 	int rv;
 
 	rv = regmap_read(drvdata->lpaif_map,
-			LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
+			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
 	if (rv) {
 		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
 				__func__, rv);
@@ -362,7 +370,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -375,7 +383,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -389,7 +397,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -444,6 +452,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
@@ -464,14 +473,14 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);
+			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 				__func__, ret);
 		return ret;
 	}
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 5c99b3d..fa00be4 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -43,9 +43,37 @@ struct lpass_data {
 
 	/* interrupts from the low-power audio interface (LPAIF) */
 	int lpaif_irq;
+
+	/* SOC specific variations in the LPASS IP integration */
+	struct lpass_variant *variant;
+};
+
+/* Vairant data per each SOC */
+struct lpass_variant {
+	u32	i2sctrl_reg_base;
+	u32	i2sctrl_reg_stride;
+	u32	i2s_ports;
+	u32	irq_reg_base;
+	u32	irq_reg_stride;
+	u32	irq_ports;
+	u32	rdma_reg_base;
+	u32	rdma_reg_stride;
+	u32	rdma_channels;
+
+	/* SOC specific intialization like clocks */
+	int (*init)(struct platform_device *pdev);
+	int (*exit)(struct platform_device *pdev);
+
+	/* SOC specific dais */
+	struct snd_soc_dai_driver *dai_driver;
+	int num_dai;
 };
 
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
+extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
 
 #endif /* __LPASS_H__ */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 03/13] ASoC: qcom: remove hardcoded i2s port number
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
@ 2015-05-13 12:00   ` Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
                     ` (9 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:00 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch attempts to remove the hardcoded i2s port number in lpass
driver. Now the the port number comes from the dai id field.

This will allow other SOCs to use different port numbers on the lpass
driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c     | 16 +++++++---------
 sound/soc/qcom/lpass-ipq806x.c |  1 +
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 2c20927..5965667 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -138,8 +138,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S),
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -164,8 +163,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
+			   0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -180,7 +179,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(drvdata->variant, LPAIF_I2S_PORT_MI2S),
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -201,7 +200,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_I2SCTL_REG(drvdata->variant,
-				LPAIF_I2S_PORT_MI2S),
+						dai->driver->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -213,7 +212,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_I2SCTL_REG(drvdata->variant,
-				LPAIF_I2S_PORT_MI2S),
+						dai->driver->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -243,8 +242,7 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S), 0);
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index d1f698c..9483273 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -43,6 +43,7 @@ enum lpaif_dma_channels {
 };
 
 static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
+	.id	= IPQ806X_LPAIF_I2S_PORT_MI2S,
 	.playback = {
 		.stream_name	= "lpass-cpu-playback",
 		.formats	= SNDRV_PCM_FMTBIT_S16 |
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 04/13] ASoC: qcom: remove hardcoded dma channel
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (2 preceding siblings ...)
  2015-05-13 12:00   ` [PATCH v1 03/13] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
@ 2015-05-13 12:00   ` Srinivas Kandagatla
  2015-05-13 12:00   ` [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
                     ` (8 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:00 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch removes hardcoded dma channel value in lpass driver, Now the
dma channel allocation happens in the SOC specific layer. This will
allow different LPASS integrations to use the lpass driver in more
generic way.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-ipq806x.c  | 12 ++++++
 sound/soc/qcom/lpass-platform.c | 93 ++++++++++++++++++++++++++++-------------
 sound/soc/qcom/lpass.h          |  2 +
 3 files changed, 77 insertions(+), 30 deletions(-)

diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 9483273..ad1d67a 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -63,6 +63,16 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
 	.ops    = &asoc_qcom_lpass_cpu_dai_ops,
 };
 
+int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+	return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
+}
+
+int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+	return 0;
+}
+
 struct lpass_variant ipq806x_data = {
 	.i2sctrl_reg_base	= 0x0010,
 	.i2sctrl_reg_stride	= 0x04,
@@ -75,6 +85,8 @@ struct lpass_variant ipq806x_data = {
 	.rdma_channels		= 4,
 	.dai_driver		= &ipq806x_lpass_cpu_dai_driver,
 	.num_dai		= 1,
+	.alloc_dma_channel	= ipq806x_lpass_alloc_dma_channel,
+	.free_dma_channel	= ipq806x_lpass_free_dma_channel,
 };
 
 static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a38e7ec..fc08891 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -24,6 +24,11 @@
 #include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
+struct lpass_pcm_data {
+	int rdma_ch;
+	int i2s_port;
+};
+
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
 
@@ -78,6 +83,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
@@ -85,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret;
+	int ret, rdma_port = pcm_data->i2s_port;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -95,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
-			LPAIF_RDMACTL_AUDINTF_MI2S |
+			LPAIF_RDMACTL_AUDINTF(rdma_port) |
 			LPAIF_RDMACTL_FIFOWM_8;
 
 	switch (bitwidth) {
@@ -151,7 +157,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), regval);
+			LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -164,13 +170,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -182,13 +189,14 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABASE_REG(v, ch),
 			runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -197,7 +205,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABUFF_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABUFF_REG(v, ch),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -206,7 +214,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMAPER_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMAPER_REG(v, ch),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -215,7 +223,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMACTL_REG(v, ch),
 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -230,10 +238,11 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		int cmd)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -242,7 +251,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		/* clear status before enabling interrupts */
 		ret = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ALL(ch));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, ret);
@@ -251,8 +260,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ALL(ch),
+				LPAIF_IRQ_ALL(ch));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 					__func__, ret);
@@ -260,7 +269,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, ch),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_ON);
 		if (ret) {
@@ -273,7 +282,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, ch),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_OFF);
 		if (ret) {
@@ -284,7 +293,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
+				LPAIF_IRQ_ALL(ch), 0);
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 					__func__, ret);
@@ -300,15 +309,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	ret = regmap_read(drvdata->lpaif_map,
-			 LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
-			 &base_addr);
+			LPAIF_RDMABASE_REG(v, ch), &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
 				__func__, ret);
@@ -316,8 +325,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	}
 
 	ret = regmap_read(drvdata->lpaif_map,
-			 LPAIF_RDMACURR_REG(v, LPAIF_RDMA_CHAN_MI2S),
-			 &curr_addr);
+			LPAIF_RDMACURR_REG(v, ch), &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
 				__func__, ret);
@@ -355,9 +363,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
-	int rv;
+	int rv, chan = pcm_data->rdma_ch;
 
 	rv = regmap_read(drvdata->lpaif_map,
 			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
@@ -366,12 +375,13 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 				__func__, rv);
 		return IRQ_NONE;
 	}
-	interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);
 
-	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
+	interrupts &= LPAIF_IRQ_ALL(chan);
+
+	if (interrupts & LPAIF_IRQ_PER(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_PER(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -381,10 +391,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
-	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
+	if (interrupts & LPAIF_IRQ_XRUN(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_XRUN(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -395,10 +405,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
-	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
+	if (interrupts & LPAIF_IRQ_ERR(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ERR(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -450,10 +460,26 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	struct snd_pcm *pcm = soc_runtime->pcm;
 	struct snd_pcm_substream *substream =
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	int ret;
+	struct lpass_pcm_data *data;
+
+	data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (v->alloc_dma_channel)
+		data->rdma_ch = v->alloc_dma_channel(drvdata);
+
+	if (IS_ERR_VALUE(data->rdma_ch))
+		return data->rdma_ch;
+
+	data->i2s_port = cpu_dai->driver->id;
+
+	snd_soc_pcm_set_drvdata(soc_runtime, data);
 
 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 	soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
@@ -480,7 +506,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		return ret;
 	}
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -499,6 +525,13 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	struct snd_pcm_substream *substream =
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_data *drvdata =
+		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
+	struct lpass_variant *v = drvdata->variant;
+
+	if (v->free_dma_channel)
+		v->free_dma_channel(drvdata, data->rdma_ch);
 
 	lpass_platform_free_buffer(substream, soc_runtime);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index fa00be4..caaf17f 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -63,6 +63,8 @@ struct lpass_variant {
 	/* SOC specific intialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
+	int (*alloc_dma_channel)(struct lpass_data *data);
+	int (*free_dma_channel)(struct lpass_data *data, int ch);
 
 	/* SOC specific dais */
 	struct snd_soc_dai_driver *dai_driver;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (3 preceding siblings ...)
  2015-05-13 12:00   ` [PATCH v1 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
@ 2015-05-13 12:00   ` Srinivas Kandagatla
  2015-05-15  5:23     ` Kenneth Westfield
  2015-05-13 12:02   ` [PATCH v1 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
                     ` (7 subsequent siblings)
  12 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:00 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds support to allow bitclk and osrclk per i2s dai port.
on APQ8016 there are 4 i2s ports each one has its own bit clks.

Without this patch its not possible to support multiple i2s ports in the
lpass driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 54 ++++++++++++++++++++++++++++++----------------
 sound/soc/qcom/lpass.h     |  5 +++--
 2 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 5965667..0d28ea7 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
+	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
 	if (ret)
 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
 				__func__, freq, ret);
@@ -47,18 +47,18 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_prepare_enable(drvdata->mi2s_osr_clk);
+	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
 				__func__, ret);
 		return ret;
 	}
 
-	ret = clk_prepare_enable(drvdata->mi2s_bit_clk);
+	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
 				__func__, ret);
-		clk_disable_unprepare(drvdata->mi2s_osr_clk);
+		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 		return ret;
 	}
 
@@ -70,8 +70,8 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
-	clk_disable_unprepare(drvdata->mi2s_bit_clk);
-	clk_disable_unprepare(drvdata->mi2s_osr_clk);
+	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
+	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -146,7 +146,8 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
-	ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2);
+	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
+			   rate * bitwidth * 2);
 	if (ret) {
 		dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
 				__func__, rate * bitwidth * 2, ret);
@@ -354,7 +355,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	struct lpass_variant *variant;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
-	int ret;
+	char clk_name[16];
+	int ret, i;
 
 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
 	if (dsp_of_node) {
@@ -400,18 +402,34 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	if (variant->init)
 		variant->init(pdev);
 
-	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
-	if (IS_ERR(drvdata->mi2s_osr_clk)) {
-		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_osr_clk));
-		return PTR_ERR(drvdata->mi2s_osr_clk);
+	for (i = 0; i < variant->num_dai; i++) {
+		if (variant->num_dai > 1)
+			sprintf(clk_name, "mi2s-osr-clk%d", i);
+		else
+			sprintf(clk_name, "mi2s-osr-clk");
+
+		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(drvdata->mi2s_osr_clk[i])) {
+			dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->mi2s_osr_clk[i]));
+			return PTR_ERR(drvdata->mi2s_osr_clk[i]);
+		}
 	}
 
-	drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");
-	if (IS_ERR(drvdata->mi2s_bit_clk)) {
-		dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_bit_clk));
-		return PTR_ERR(drvdata->mi2s_bit_clk);
+	for (i = 0; i < variant->num_dai; i++) {
+
+		if (variant->num_dai > 1)
+			sprintf(clk_name, "mi2s-bit-clk%d", i);
+		else
+			sprintf(clk_name, "mi2s-bit-clk");
+
+		drvdata->mi2s_bit_clk[i] = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(drvdata->mi2s_bit_clk[i])) {
+			dev_err(&pdev->dev,
+				"%s() error getting mi2s-bit-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
+			return PTR_ERR(drvdata->mi2s_bit_clk[i]);
+		}
 	}
 
 	drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index caaf17f..75e9370 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -22,6 +22,7 @@
 #include <linux/regmap.h>
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
+#define LPASS_MAX_MI2S_PORTS			(8)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -30,10 +31,10 @@ struct lpass_data {
 	struct clk *ahbix_clk;
 
 	/* MI2S system clock */
-	struct clk *mi2s_osr_clk;
+	struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];
 
 	/* MI2S bit clock (derived from system clock by a divider */
-	struct clk *mi2s_bit_clk;
+	struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
 
 	/* low-power audio interface (LPAIF) registers */
 	void __iomem *lpaif;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 06/13] ASoC: qcom: make osr clock optional
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (4 preceding siblings ...)
  2015-05-13 12:00   ` [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
@ 2015-05-13 12:02   ` Srinivas Kandagatla
  2015-05-13 12:02   ` [PATCH v1 07/13] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:02 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

Some LPASS integrations like on APQ8016 do not have OSR clk, so making
osr clk optional would allow such integrations to use lpass driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 33 ++++++++++++++++++++++-----------
 1 file changed, 22 insertions(+), 11 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 0d28ea7..33e28370 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,6 +33,9 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
+	if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+		return 0;
+
 	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
 	if (ret)
 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
@@ -47,18 +50,22 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
-	if (ret) {
-		dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
-				__func__, ret);
-		return ret;
+	if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {
+		ret = clk_prepare_enable(
+				drvdata->mi2s_osr_clk[dai->driver->id]);
+		if (ret) {
+			dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
+					__func__, ret);
+			return ret;
+		}
 	}
 
 	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
 				__func__, ret);
-		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
+		if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+			clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 		return ret;
 	}
 
@@ -71,7 +78,9 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
 	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
-	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
+
+	if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -408,11 +417,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 		else
 			sprintf(clk_name, "mi2s-osr-clk");
 
-		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev, clk_name);
+		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev,
+								clk_name);
 		if (IS_ERR(drvdata->mi2s_osr_clk[i])) {
-			dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_osr_clk[i]));
-			return PTR_ERR(drvdata->mi2s_osr_clk[i]);
+			dev_err(&pdev->dev,
+				"%s() error getting mi2s-osr-clk: %ld\n",
+				__func__,
+				PTR_ERR(drvdata->mi2s_osr_clk[i]));
 		}
 	}
 
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 07/13] ASoC: qcom: add dma channel control offset to variant data
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (5 preceding siblings ...)
  2015-05-13 12:02   ` [PATCH v1 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
@ 2015-05-13 12:02   ` Srinivas Kandagatla
  2015-05-13 12:02   ` [PATCH v1 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
                     ` (5 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:02 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds ability to pass dma channel control bits start offset, which
differ in differnet qcom SOCs. On apq8016 dma channel control bits start
after an offset of 1.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 2 +-
 sound/soc/qcom/lpass.h          | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index fc08891..8ab0ac1 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret, rdma_port = pcm_data->i2s_port;
+	int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 75e9370..023170a 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -61,6 +61,11 @@ struct lpass_variant {
 	u32	rdma_reg_stride;
 	u32	rdma_channels;
 
+	/**
+	 * on SOCs like APQ8016 the channel control bits start
+	 * at different offset to ipq806x
+	 **/
+	u32	rdmactl_audif_start;
 	/* SOC specific intialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (6 preceding siblings ...)
  2015-05-13 12:02   ` [PATCH v1 07/13] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
@ 2015-05-13 12:02   ` Srinivas Kandagatla
  2015-05-13 12:02   ` [PATCH v1 09/13] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:02 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds ablity to lpass driver to handle interrupt per dma
channel. Without this patch its not possible to use multipl ports on the
lpass.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 94 ++++++++++++++++++++++++++---------------
 sound/soc/qcom/lpass.h          |  4 ++
 2 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 8ab0ac1..79688aa 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -356,27 +356,15 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = {
 	.mmap		= lpass_platform_pcmops_mmap,
 };
 
-static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+static irqreturn_t lpass_dma_interrupt_handler(
+			struct snd_pcm_substream *substream,
+			struct lpass_data *drvdata,
+			int chan, u32 interrupts)
 {
-	struct snd_pcm_substream *substream = data;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
-	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
-	int rv, chan = pcm_data->rdma_ch;
-
-	rv = regmap_read(drvdata->lpaif_map,
-			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
-	if (rv) {
-		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
-				__func__, rv);
-		return IRQ_NONE;
-	}
-
-	interrupts &= LPAIF_IRQ_ALL(chan);
+	int rv;
 
 	if (interrupts & LPAIF_IRQ_PER(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
@@ -422,6 +410,35 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	return ret;
 }
 
+static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->lpaif_map,
+			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
+	if (rv) {
+		pr_err("%s() error reading from irqstat reg: %d\n",
+				__func__, rv);
+		return IRQ_NONE;
+	}
+
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
 		struct snd_soc_pcm_runtime *soc_runtime)
 {
@@ -477,6 +494,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (IS_ERR_VALUE(data->rdma_ch))
 		return data->rdma_ch;
 
+	drvdata->substream[data->rdma_ch] = substream;
 	data->i2s_port = cpu_dai->driver->id;
 
 	snd_soc_pcm_set_drvdata(soc_runtime, data);
@@ -488,29 +506,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (ret)
 		return ret;
 
-	ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
-			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
-			"lpass-irq-lpaif", substream);
-	if (ret) {
-		dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
-				__func__, ret);
-		goto err_buf;
-	}
-
-	/* ensure audio hardware is disabled */
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
-	if (ret) {
-		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
-				__func__, ret);
-		return ret;
-	}
 	ret = regmap_write(drvdata->lpaif_map,
 			LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
-		return ret;
+		goto err_buf;
 	}
 
 	return 0;
@@ -530,6 +531,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_variant *v = drvdata->variant;
 
+	drvdata->substream[data->rdma_ch] = NULL;
+
 	if (v->free_dma_channel)
 		v->free_dma_channel(drvdata, data->rdma_ch);
 
@@ -545,6 +548,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = {
 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct lpass_variant *v = drvdata->variant;
+	int ret;
 
 	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
 	if (drvdata->lpaif_irq < 0) {
@@ -553,6 +558,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	/* ensure audio hardware is disabled */
+	ret = regmap_write(drvdata->lpaif_map,
+			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
+			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
+			"lpass-irq-lpaif", drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() irq request failed: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+
 	return devm_snd_soc_register_platform(&pdev->dev,
 			&lpass_platform_driver);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 023170a..d572e7b 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -23,6 +23,7 @@
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
 #define LPASS_MAX_MI2S_PORTS			(8)
+#define LPASS_MAX_DMA_CHANNELS			(8)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -47,6 +48,9 @@ struct lpass_data {
 
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
+
+	/* used it for handling interrupt per dma channel */
+	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 };
 
 /* Vairant data per each SOC */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 09/13] ASoC: qcom: add bit map to track static dma channel allocations
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (7 preceding siblings ...)
  2015-05-13 12:02   ` [PATCH v1 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
@ 2015-05-13 12:02   ` Srinivas Kandagatla
  2015-05-13 12:03   ` [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
                     ` (3 subsequent siblings)
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:02 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds dma channel bit mask to lpass data to keep track of dma
channel allocations. This flag would be used in apq8016 lpass driver.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index d572e7b..deecae9 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -49,6 +49,9 @@ struct lpass_data {
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
 
+	/* bit map to keep track of static channel allocations */
+	unsigned long rdma_ch_bit_map;
+
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (8 preceding siblings ...)
  2015-05-13 12:02   ` [PATCH v1 09/13] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
@ 2015-05-13 12:03   ` Srinivas Kandagatla
  2015-05-15  5:23     ` Kenneth Westfield
  2015-05-13 12:03   ` [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
                     ` (2 subsequent siblings)
  12 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:03 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds apq8016 lpass driver support. APQ8016 has 4 MI2S which
can be routed to one internal codec and 2 external codec interfaces.

Primary, Secondary, Quaternary I2S can do Rx(playback) and Tertiary and
Quaternary can do Tx(capture).

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 include/dt-bindings/sound/apq8016-lpass.h |   9 ++
 sound/soc/qcom/Kconfig                    |   6 +
 sound/soc/qcom/Makefile                   |   2 +
 sound/soc/qcom/lpass-apq8016.c            | 242 ++++++++++++++++++++++++++++++
 sound/soc/qcom/lpass.h                    |   4 +
 5 files changed, 263 insertions(+)
 create mode 100644 include/dt-bindings/sound/apq8016-lpass.h
 create mode 100644 sound/soc/qcom/lpass-apq8016.c

diff --git a/include/dt-bindings/sound/apq8016-lpass.h b/include/dt-bindings/sound/apq8016-lpass.h
new file mode 100644
index 0000000..499076e
--- /dev/null
+++ b/include/dt-bindings/sound/apq8016-lpass.h
@@ -0,0 +1,9 @@
+#ifndef __DT_APQ8016_LPASS_H
+#define __DT_APQ8016_LPASS_H
+
+#define MI2S_PRIMARY	0
+#define MI2S_SECONDARY	1
+#define MI2S_TERTIARY	2
+#define MI2S_QUATERNARY	3
+
+#endif /* __DT_APQ8016_LPASS_H */
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 865205e..9cc5ed7 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,12 @@ config SND_SOC_LPASS_IPQ806X
 	select SND_SOC_LPASS_CPU
 	select SND_SOC_LPASS_PLATFORM
 
+config SND_SOC_LPASS_APQ8016
+	tristate
+	depends on SND_SOC_QCOM
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index f8aab91..ac76308 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -2,10 +2,12 @@
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
+snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
+obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 
 # Machine
 snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
new file mode 100644
index 0000000..5cbf17f0
--- /dev/null
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ *
+ * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
+ *
+ */
+
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include <dt-bindings/sound/apq8016-lpass.h>
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
+	[MI2S_PRIMARY] =  {
+		.id = MI2S_PRIMARY,
+		.name = "Primary MI2S",
+		.playback = {
+			.stream_name	= "Primary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	[MI2S_SECONDARY] =  {
+		.id = MI2S_SECONDARY,
+		.name = "Secondary MI2S",
+		.playback = {
+			.stream_name	= "Secondary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	[MI2S_TERTIARY] =  {
+		.id = MI2S_TERTIARY,
+		.name = "Tertiary MI2S",
+		.capture = {
+			.stream_name	= "Tertiary Capture",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	[MI2S_QUATERNARY] =  {
+		.id = MI2S_QUATERNARY,
+		.name = "Quatenary MI2S",
+		.playback = {
+			.stream_name	= "Quatenary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.capture = {
+			.stream_name	= "Quatenary Capture",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+};
+
+static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+	struct lpass_variant *v = drvdata->variant;
+	int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,
+					v->rdma_channels);
+
+	if (chan >= v->rdma_channels)
+		return -EBUSY;
+
+	set_bit(chan, &drvdata->rdma_ch_bit_map);
+
+	return chan;
+}
+
+static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+	clear_bit(chan, &drvdata->rdma_ch_bit_map);
+
+	return 0;
+}
+
+static int apq8016_lpass_init(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
+	if (IS_ERR(drvdata->pcnoc_mport_clk)) {
+		dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->pcnoc_mport_clk));
+		return PTR_ERR(drvdata->pcnoc_mport_clk);
+	}
+
+	ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
+	if (IS_ERR(drvdata->pcnoc_sway_clk)) {
+		dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->pcnoc_sway_clk));
+		return PTR_ERR(drvdata->pcnoc_sway_clk);
+	}
+
+	ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int apq8016_lpass_exit(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(drvdata->pcnoc_mport_clk);
+	clk_disable_unprepare(drvdata->pcnoc_sway_clk);
+
+	return 0;
+}
+
+
+struct lpass_variant apq8016_data = {
+	.i2sctrl_reg_base	= 0x1000,
+	.i2sctrl_reg_stride	= 0x1000,
+	.i2s_ports		= 4,
+	.irq_reg_base		= 0x6000,
+	.irq_reg_stride		= 0x1000,
+	.irq_ports		= 3,
+	.rdma_reg_base		= 0x8400,
+	.rdma_reg_stride	= 0x1000,
+	.rdma_channels		= 2,
+	.rdmactl_audif_start	= 1,
+	.dai_driver		= apq8016_lpass_cpu_dai_driver,
+	.num_dai		= ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
+	.init			= apq8016_lpass_init,
+	.exit			= apq8016_lpass_exit,
+	.alloc_dma_channel	= apq8016_lpass_alloc_dma_channel,
+	.free_dma_channel	= apq8016_lpass_free_dma_channel,
+};
+
+static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
+	{ .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
+
+static struct platform_driver apq8016_lpass_cpu_platform_driver = {
+	.driver	= {
+		.name		= "apq8016-lpass-cpu",
+		.of_match_table	= of_match_ptr(apq8016_lpass_cpu_device_id),
+	},
+	.probe	= asoc_qcom_lpass_cpu_platform_probe,
+	.remove	= asoc_qcom_lpass_cpu_platform_remove,
+};
+module_platform_driver(apq8016_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index deecae9..d6e86c1 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -54,6 +54,10 @@ struct lpass_data {
 
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
+
+	/* 8016 specific */
+	struct clk *pcnoc_mport_clk;
+	struct clk *pcnoc_sway_clk;
 };
 
 /* Vairant data per each SOC */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (9 preceding siblings ...)
  2015-05-13 12:03   ` [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
@ 2015-05-13 12:03   ` Srinivas Kandagatla
  2015-05-15  5:23     ` Kenneth Westfield
  2015-05-13 12:03   ` [PATCH v1 12/13] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
  2015-05-13 12:03   ` [PATCH v1 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings Srinivas Kandagatla
  12 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:03 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds apq8016 machine driver support. This patch was tested on
two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
features.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig       |   9 ++
 sound/soc/qcom/Makefile      |   2 +
 sound/soc/qcom/apq8016_sbc.c | 215 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 226 insertions(+)
 create mode 100644 sound/soc/qcom/apq8016_sbc.c

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 9cc5ed7..e71b0f2 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -34,3 +34,12 @@ config SND_SOC_STORM
 	help
           Say Y or M if you want add support for SoC audio on the
           Qualcomm Technologies IPQ806X-based Storm board.
+
+config SND_SOC_APQ8016_SBC
+	tristate "SoC Audio support for APQ8016 SBC platforms"
+	depends on SND_SOC_QCOM || ARCH_QCOM || COMPILE_TEST
+	select SND_SOC_LPASS_APQ8016
+	help
+          Support for Qualcomm Technologies LPASS audio block in
+          APQ8016 SOC-based systems.
+          Say Y if you want to use audio devices on MI2S
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index ac76308..79e5c50 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -11,5 +11,7 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 
 # Machine
 snd-soc-storm-objs := storm.o
+snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
+obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
new file mode 100644
index 0000000..8958633
--- /dev/null
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <dt-bindings/sound/apq8016-lpass.h>
+
+struct apq8016_sbc_data {
+	void __iomem *mic_iomux;
+	void __iomem *spkr_iomux;
+	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
+};
+
+#define MIC_CTRL_QUA_WS_SLAVE_SEL_10	BIT(17)
+#define MIC_CTRL_TLMM_SCLK_EN		BIT(1)
+#define	SPKR_CTL_PRI_WS_SLAVE_SEL_11	(BIT(17) | BIT(16))
+
+static int apq8016_sbc_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_card *card = rtd->card;
+	struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
+
+	if (cpu_dai->id == MI2S_QUATERNARY) {
+		/* Configure the Quat MI2S to TLMM */
+		writel(readl(pdata->mic_iomux) |
+			MIC_CTRL_QUA_WS_SLAVE_SEL_10 |
+			MIC_CTRL_TLMM_SCLK_EN,
+			pdata->mic_iomux);
+
+		return 0;
+	} else if (cpu_dai->id == MI2S_PRIMARY) {
+		writel(readl(pdata->spkr_iomux) |
+			SPKR_CTL_PRI_WS_SLAVE_SEL_11,
+			pdata->spkr_iomux);
+
+		return 0;
+	}
+
+	dev_err(card->dev, "unsupported cpu dai configuration\n");
+
+	return -EINVAL;
+}
+
+static struct snd_soc_ops apq8016_sbc_soc_ops = {
+	.startup	= apq8016_sbc_startup,
+};
+
+static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
+{
+	int num_links;
+	struct device *dev = card->dev;
+	struct snd_soc_dai_link *dai_link;
+	struct device_node *np, *codec, *cpu, *node  = dev->of_node;
+	struct apq8016_sbc_data *data;
+	char *name;
+	int ret;
+
+	/* Populate links */
+	num_links = of_get_child_count(node);
+
+	/* Allocate the private data and the DAI link array */
+	data = devm_kzalloc(dev, sizeof(*data) + sizeof(*dai_link) * num_links,
+			    GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	card->dai_link	= &data->dai_link[0];
+	card->num_links	= num_links;
+
+	dai_link = data->dai_link;
+
+	for_each_child_of_node(node, np) {
+		cpu = of_get_child_by_name(np, "cpu");
+		codec = of_get_child_by_name(np, "codec");
+
+		if (!cpu || !codec) {
+			dev_err(dev, "Can't find cpu/codec DT node\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		dai_link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+		if (!dai_link->cpu_of_node) {
+			dev_err(card->dev, "error getting cpu phandle\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		dai_link->codec_of_node = of_parse_phandle(codec,
+							   "sound-dai",
+							   0);
+		if (!dai_link->codec_of_node) {
+			dev_err(card->dev, "error getting codec phandle\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		ret = snd_soc_of_get_dai_name(cpu, &dai_link->cpu_dai_name);
+		if (ret) {
+			dev_err(card->dev, "error getting cpu dai name\n");
+			return ERR_PTR(ret);
+		}
+
+		ret = snd_soc_of_get_dai_name(codec, &dai_link->codec_dai_name);
+		if (ret) {
+			dev_err(card->dev, "error getting codec dai name\n");
+			return ERR_PTR(ret);
+		}
+
+		dai_link->platform_of_node = dai_link->cpu_of_node;
+		/* For now we only support playback */
+		dai_link->playback_only = true;
+
+		if (of_property_read_bool(np, "external"))
+			name = "HDMI";
+
+		else
+			name = "Headset";
+
+		dai_link->ops = &apq8016_sbc_soc_ops;
+		dai_link->name = dai_link->stream_name = name;
+
+		dai_link++;
+	}
+
+	return data;
+}
+
+static int apq8016_sbc_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card;
+	struct apq8016_sbc_data *data;
+	struct resource *res;
+	int ret;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->dev = dev;
+	data = apq8016_sbc_parse_of(card);
+	if (IS_ERR(data)) {
+		dev_err(&pdev->dev, "Error resolving dai links: %ld\n",
+			PTR_ERR(data));
+		return PTR_ERR(data);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux");
+	data->mic_iomux = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->mic_iomux))
+		return PTR_ERR(data->mic_iomux);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spkr-iomux");
+	data->spkr_iomux = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->spkr_iomux))
+		return PTR_ERR(data->spkr_iomux);
+
+	platform_set_drvdata(pdev, data);
+	snd_soc_card_set_drvdata(card, data);
+
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret) {
+		dev_err(&pdev->dev, "Error parsing card name: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret == -EPROBE_DEFER) {
+		card->dev = NULL;
+		return ret;
+	} else if (ret) {
+		dev_err(&pdev->dev, "Error registering soundcard: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id apq8016_sbc_device_id[]  = {
+	{ .compatible = "qcom,apq8016-sbc-sndcard" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, apq8016_sbc_device_id);
+
+static struct platform_driver apq8016_sbc_platform_driver = {
+	.driver = {
+		.name = "qcom-apq8016-sbc",
+		.of_match_table = of_match_ptr(apq8016_sbc_device_id),
+	},
+	.probe = apq8016_sbc_platform_probe,
+};
+module_platform_driver(apq8016_sbc_platform_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 12/13] ASoC: qcom: Document apq8016 bindings.
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (10 preceding siblings ...)
  2015-05-13 12:03   ` [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
@ 2015-05-13 12:03   ` Srinivas Kandagatla
  2015-05-13 12:03   ` [PATCH v1 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings Srinivas Kandagatla
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:03 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch updates lpass bindings with apq8016 specific bindings.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index e00732d..21c6483 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
 
 Required properties:
 
-- compatible		: "qcom,lpass-cpu"
+- compatible		: "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
 - clocks		: Must contain an entry for each entry in clock-names.
 - clock-names		: A list which must include the following entries:
 				* "ahbix-clk"
 				* "mi2s-osr-clk"
 				* "mi2s-bit-clk"
+			: required clocks for "qcom,lpass-cpu-apq8016"
+				* "ahbix-clk"
+				* "mi2s-bit-clk0"
+				* "mi2s-bit-clk1"
+				* "mi2s-bit-clk2"
+				* "mi2s-bit-clk3"
+				* "pcnoc-mport-clk"
+				* "pcnoc-sway-clk"
+
 - interrupts		: Must contain an entry for each entry in
 			  interrupt-names.
 - interrupt-names	: A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
 - reg-names		: A list which must include the following entries:
 				* "lpass-lpaif"
 
+
+
 Optional properties:
 
 - qcom,adsp		: Phandle for the audio DSP node
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v1 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
                     ` (11 preceding siblings ...)
  2015-05-13 12:03   ` [PATCH v1 12/13] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
@ 2015-05-13 12:03   ` Srinivas Kandagatla
  12 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-13 12:03 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds bindings for apq8016 sbc machine driver.
On APQ8016 4 MI2S can be configured to different sinks like internal
codec/external codec, this connection is controlled via 2 iomux
registers.

Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/sound/qcom,apq8016-sbc.txt | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt

diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
new file mode 100644
index 0000000..01d62be
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
@@ -0,0 +1,61 @@
+* Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+Required properties:
+
+- compatible		: "qcom,apq8016-sbc-sndcard"
+
+- pinctrl-N		: One property must exist for each entry in
+			  pinctrl-names.  See ../pinctrl/pinctrl-bindings.txt
+			  for details of the property values.
+- pinctrl-names		: Must contain a "default" entry.
+- reg			: Must contain an address for each entry in reg-names.
+- reg-names		: A list which must include the following entries:
+				* "mic-iomux"
+				* "spkr-iomux"
+- qcom,model		: Name of the sound card.
+
+Dai-link subnode properties and subnodes:
+
+Required dai-link subnodes:
+
+- cpu					: CPU   sub-node
+- codec					: CODEC sub-node
+
+Required CPU/CODEC subnodes properties:
+
+-sound-dai		: phandle and port of CPU/CODEC
+-capture-dai		: phandle and port of CPU/CODEC
+
+Optional CPU/CODEC subnodes properties:
+- external	: flag to indicate if the I2S is connected to external codec
+Example:
+
+sound: sound {
+	compatible = "qcom,apq8016-sbc-sndcard";
+	reg = <0x07702000 0x4>, <0x07702004 0x4>;
+	reg-names = "mic-iomux", "spkr-iomux";
+	qcom,model = "DB410c";
+
+	/* I2S - Internal codec */
+	internal-dai-link@0 {
+		cpu { /* PRIMARY */
+			sound-dai = <&lpass MI2S_PRIMARY>;
+		};
+		codec {
+			sound-dai = <&wcd_codec 0>;
+		};
+	};
+
+	/* External Primary or External Secondary -ADV7533 HDMI */
+	external-dai-link@0 {
+		external;
+		cpu { /* QUAT */
+			sound-dai = <&lpass MI2S_QUATERNARY>;
+		};
+		codec {
+			sound-dai = <&adv_bridge 0>;
+		};
+	};
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [alsa-devel] [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio
  2015-05-12 17:04           ` Lars-Peter Clausen
@ 2015-05-14  7:55             ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-14  7:55 UTC (permalink / raw)
  To: Lars-Peter Clausen, Patrick Lai, Mark Brown, Rob Herring,
	Pawel Moll, Ian Campbell, Kumar Gala, Banajit Goswami,
	Liam Girdwood, Jaroslav Kysela, Takashi Iwai, devicetree,
	linux-kernel, alsa-devel, linux-arm-msm



On 12/05/15 18:04, Lars-Peter Clausen wrote:
>>
>> Its not clear from code, why should we enter to legacy naming if the dais
>> count == 1 even-though the dai_drv has has valid name and id information.
>>
>> Mark/Lars,
>>
>> I can workaround this by using dai->driver->id in the driver, But do you
>> think that dai name and id should be assigned from dai drv if present?
>
> I think it should be OK to extend that if condition to
>
> if (count == 1 && dai_drv[0].id == 0 && legacy_dai_naming) ...
>
> It doesn't look like any of the systems for which we currently take the
> legacy path do set id to non 0. And the less new systems following
> legacy naming scheme the better.
>
Thanks Lars, will send out an RFC patch and see what other people thing.

--srini
> - Lars

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port
  2015-05-13 12:00   ` [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
@ 2015-05-15  5:23     ` Kenneth Westfield
  2015-05-15  8:44       ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-15  5:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Wed, May 13, 2015 at 05:00:52AM -0700, Srinivas Kandagatla wrote:
> This patch adds support to allow bitclk and osrclk per i2s dai port.
> on APQ8016 there are 4 i2s ports each one has its own bit clks.
> 
> Without this patch its not possible to support multiple i2s ports in the
> lpass driver.

> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 5965667..0d28ea7 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct
> snd_soc_dai *dai, int clk_id,
>  	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>  	int ret;
>  
> -	ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
> +	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
>  	if (ret)
>  		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u:
> %d\n",
>  				__func__, freq, ret);

Audio was broken on the Storm board with this patch series.  The issue
has to do with the mismatch of the clock position in the array (which
was 0) and the dai->driver->id (which was 4).  Basically, the position of
the bit/osr clocks in their respective arrays need to match the MI2S
port number, even if the port number doesn't start at the 0 position.

I realize there are multiple ways to address this.  The quick solution I
came up with (to get audio functioning again) was to change the DT clock
entries for the ipq806x (see changes below for your reference).  The
downside to the way I did this is, that now, there is no error-checking
for clocks that should be in the DT but aren't there.

Suggestions are welcome on how to best address this issue.

-----------------------><---------------------------------------------
diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index 21c6483..2684a4f 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -8,8 +8,8 @@ Required properties:
 - clocks		: Must contain an entry for each entry in clock-names.
 - clock-names		: A list which must include the following entries:
 				* "ahbix-clk"
-				* "mi2s-osr-clk"
-				* "mi2s-bit-clk"
+				* "mi2s-osr-clk4"
+				* "mi2s-bit-clk4"
 			: required clocks for "qcom,lpass-cpu-apq8016"
 				* "ahbix-clk"
 				* "mi2s-bit-clk0"
@@ -42,7 +42,7 @@ Example:
 lpass@28100000 {
 	compatible = "qcom,lpass-cpu";
 	clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>;
-	clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk";
+	clock-names = "ahbix-clk", "mi2s-osr-clk4", "mi2s-bit-clk4";
 	interrupts = <0 85 1>;
 	interrupt-names = "lpass-irq-lpaif";
 	pinctrl-names = "default", "idle";
diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
index 5a13366..090984f 100644
--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
@@ -189,8 +189,8 @@
 					<&lcc MI2S_OSR_CLK>,
 					<&lcc MI2S_BIT_CLK>;
 			clock-names = "ahbix-clk",
-					"mi2s-osr-clk",
-					"mi2s-bit-clk";
+					"mi2s-osr-clk4",
+					"mi2s-bit-clk4";
 			interrupts = <0 85 1>;
 			interrupt-names = "lpass-irq-lpaif";
 			reg = <0x28100000 0x10000>;
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 5053629..7b66e52 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -411,11 +411,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	if (variant->init)
 		variant->init(pdev);
 
-	for (i = 0; i < variant->num_dai; i++) {
-		if (variant->num_dai > 1)
-			sprintf(clk_name, "mi2s-osr-clk%d", i);
-		else
-			sprintf(clk_name, "mi2s-osr-clk");
+	for (i = 0; i < LPASS_MAX_MI2S_PORTS; i++) {
+		sprintf(clk_name, "mi2s-osr-clk%d", i);
 
 		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev,
 								clk_name);
@@ -427,19 +424,14 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 		}
 	}
 
-	for (i = 0; i < variant->num_dai; i++) {
-
-		if (variant->num_dai > 1)
-			sprintf(clk_name, "mi2s-bit-clk%d", i);
-		else
-			sprintf(clk_name, "mi2s-bit-clk");
+	for (i = 0; i < LPASS_MAX_MI2S_PORTS; i++) {
+		sprintf(clk_name, "mi2s-bit-clk%d", i);
 
 		drvdata->mi2s_bit_clk[i] = devm_clk_get(&pdev->dev, clk_name);
 		if (IS_ERR(drvdata->mi2s_bit_clk[i])) {
 			dev_err(&pdev->dev,
 				"%s() error getting mi2s-bit-clk: %ld\n",
 				__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
-			return PTR_ERR(drvdata->mi2s_bit_clk[i]);
 		}
 	}
-----------------------><---------------------------------------------

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support
  2015-05-13 12:03   ` [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
@ 2015-05-15  5:23     ` Kenneth Westfield
  2015-05-15  8:46       ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-15  5:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Wed, May 13, 2015 at 05:03:06AM -0700, Srinivas Kandagatla wrote:
> This patch adds apq8016 lpass driver support. APQ8016 has 4 MI2S which
> can be routed to one internal codec and 2 external codec interfaces.
> 
> Primary, Secondary, Quaternary I2S can do Rx(playback) and Tertiary and
> Quaternary can do Tx(capture).

> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
> index 865205e..9cc5ed7 100644
> --- a/sound/soc/qcom/Kconfig
> +++ b/sound/soc/qcom/Kconfig
> @@ -20,6 +20,12 @@ config SND_SOC_LPASS_IPQ806X
>  	select SND_SOC_LPASS_CPU
>  	select SND_SOC_LPASS_PLATFORM
>  
> +config SND_SOC_LPASS_APQ8016
> +	tristate
> +	depends on SND_SOC_QCOM
> +	select SND_SOC_LPASS_CPU
> +	select SND_SOC_LPASS_PLATFORM

Continuing from my comments on patch 2/13, should an OF dependency be added
here as well?

> +
>  config SND_SOC_STORM
>  	tristate "ASoC I2S support for Storm boards"
>  	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST

> diff --git a/sound/soc/qcom/lpass-apq8016.c
> b/sound/soc/qcom/lpass-apq8016.c
> new file mode 100644
> index 0000000..5cbf17f0
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-apq8016.c

> +static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int
> chan)
> +{
> +	clear_bit(chan, &drvdata->rdma_ch_bit_map);
> +
> +	return 0;
> +}
> +
> +static int apq8016_lpass_init(struct platform_device *pdev)
> +{
> +	struct lpass_data *drvdata = platform_get_drvdata(pdev);
> +	struct device *dev = &pdev->dev;
> +	int ret;
> +
> +	drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
> +	if (IS_ERR(drvdata->pcnoc_mport_clk)) {
> +		dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk:
> %ld\n",
> +				__func__,
> PTR_ERR(drvdata->pcnoc_mport_clk));
> +		return PTR_ERR(drvdata->pcnoc_mport_clk);
> +	}
> +
> +	ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",

Please correct the clock name in the log message ...

> +				__func__, ret);
> +		return ret;
> +	}
> +
> +	drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
> +	if (IS_ERR(drvdata->pcnoc_sway_clk)) {
> +		dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk:
> %ld\n",
> +				__func__,
> PTR_ERR(drvdata->pcnoc_sway_clk));
> +		return PTR_ERR(drvdata->pcnoc_sway_clk);
> +	}
> +
> +	ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
> +	if (ret) {
> +		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",

... here too.

> +				__func__, ret);
> +		return ret;
> +	}

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support
  2015-05-13 12:03   ` [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
@ 2015-05-15  5:23     ` Kenneth Westfield
  2015-05-15  8:47       ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-15  5:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Wed, May 13, 2015 at 05:03:14AM -0700, Srinivas Kandagatla wrote:
> This patch adds apq8016 machine driver support. This patch was tested on
> two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
> features.

> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
> index 9cc5ed7..e71b0f2 100644
> --- a/sound/soc/qcom/Kconfig
> +++ b/sound/soc/qcom/Kconfig
> @@ -34,3 +34,12 @@ config SND_SOC_STORM
>  	help
>            Say Y or M if you want add support for SoC audio on the
>            Qualcomm Technologies IPQ806X-based Storm board.
> +
> +config SND_SOC_APQ8016_SBC
> +	tristate "SoC Audio support for APQ8016 SBC platforms"
> +	depends on SND_SOC_QCOM || ARCH_QCOM || COMPILE_TEST

I believe this should be:
        depends on (SND_SOC_QCOM && ARCH_QCOM) || COMPILE_TEST

> +	select SND_SOC_LPASS_APQ8016
> +	help
> +          Support for Qualcomm Technologies LPASS audio block in
> +          APQ8016 SOC-based systems.
> +          Say Y if you want to use audio devices on MI2S

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-13 12:00   ` [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
@ 2015-05-15  5:23     ` Kenneth Westfield
  2015-05-15  8:48       ` Srinivas Kandagatla
  0 siblings, 1 reply; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-15  5:23 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Wed, May 13, 2015 at 05:00:26AM -0700, Srinivas Kandagatla wrote:
> This patch tries to make the lpass driver more generic by moving the
> ipq806x specific bits out of the cpu and platform driver, also allows the
> SOC specific drivers to add the correct register offsets.
> 
> This patch also renames the register definition header file into more
> generic header file.

> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
> index 05b9840..865205e 100644
> --- a/sound/soc/qcom/Kconfig
> +++ b/sound/soc/qcom/Kconfig

> @@ -14,11 +14,16 @@ config SND_SOC_LPASS_PLATFORM
>  	depends on SND_SOC_QCOM && OF
>  	select REGMAP_MMIO
>  
> +config SND_SOC_LPASS_IPQ806X
> +	tristate
> +	depends on SND_SOC_QCOM
> +	select SND_SOC_LPASS_CPU
> +	select SND_SOC_LPASS_PLATFORM

Based on moving the of_device_id table from lpass-cpu.c to
lpass-ipq806x.c, shouldn't the OF dependency follow to the
SND_SOC_LPASS_IPQ806X config (and not SND_SOC_LPASS_CPU)?

> +
>  config SND_SOC_STORM
>  	tristate "ASoC I2S support for Storm boards"
>  	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
> -	select SND_SOC_LPASS_CPU
> -	select SND_SOC_LPASS_PLATFORM
> +	select SND_SOC_LPASS_IPQ806X
>  	select SND_SOC_MAX98357A
>  	help
>            Say Y or M if you want add support for SoC audio on the

> diff --git a/sound/soc/qcom/lpass-ipq806x.c
> b/sound/soc/qcom/lpass-ipq806x.c
> new file mode 100644
> index 0000000..d1f698c
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-ipq806x.c

> +static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
> +	.driver	= {
> +		.name		= "lpass-cpu",
> +		.of_match_table	=
> of_match_ptr(ipq806x_lpass_cpu_device_id),
> +	},
> +	.probe	= asoc_qcom_lpass_cpu_platform_probe,
> +	.remove	= asoc_qcom_lpass_cpu_platform_remove,
> +};
> +module_platform_driver(ipq801x_lpass_cpu_platform_driver);

Patch below fixes the above typo (which breaks compilation):

-----------------------><---------------------------------------------
diff --git a/sound/soc/qcom/lpass-ipq806x.c
b/sound/soc/qcom/lpass-ipq806x.c
index ad1d67a..2eab828 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -103,7 +103,7 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
        .probe  = asoc_qcom_lpass_cpu_platform_probe,
        .remove = asoc_qcom_lpass_cpu_platform_remove,
 };
-module_platform_driver(ipq801x_lpass_cpu_platform_driver);
+module_platform_driver(ipq806x_lpass_cpu_platform_driver);
                  
 MODULE_DESCRIPTION("QTi LPASS CPU Driver");
 MODULE_LICENSE("GPL v2");
-----------------------><---------------------------------------------

> +
> +MODULE_DESCRIPTION("QTi LPASS CPU Driver");
> +MODULE_LICENSE("GPL v2");

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port
  2015-05-15  5:23     ` Kenneth Westfield
@ 2015-05-15  8:44       ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-15  8:44 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 15/05/15 06:23, Kenneth Westfield wrote:
> On Wed, May 13, 2015 at 05:00:52AM -0700, Srinivas Kandagatla wrote:
>> This patch adds support to allow bitclk and osrclk per i2s dai port.
>> on APQ8016 there are 4 i2s ports each one has its own bit clks.
>>
>> Without this patch its not possible to support multiple i2s ports in the
>> lpass driver.
>
>> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
>> index 5965667..0d28ea7 100644
>> --- a/sound/soc/qcom/lpass-cpu.c
>> +++ b/sound/soc/qcom/lpass-cpu.c
>> @@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct
>> snd_soc_dai *dai, int clk_id,
>>   	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>>   	int ret;
>>
>> -	ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
>> +	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
>>   	if (ret)
>>   		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u:
>> %d\n",
>>   				__func__, freq, ret);
>
> Audio was broken on the Storm board with this patch series.  The issue
> has to do with the mismatch of the clock position in the array (which
> was 0) and the dai->driver->id (which was 4).  Basically, the position of
> the bit/osr clocks in their respective arrays need to match the MI2S
> port number, even if the port number doesn't start at the 0 position.
>
> I realize there are multiple ways to address this.  The quick solution I
> came up with (to get audio functioning again) was to change the DT clock
> entries for the ipq806x (see changes below for your reference).  The
> downside to the way I did this is, that now, there is no error-checking
> for clocks that should be in the DT but aren't there.
>
> Suggestions are welcome on how to best address this issue.
I think all we need to do is populate the correct index in the clk 
array. TBH I don't want to change any of ipq806x bindings.

I think the below fix should be the right one, actually I did think of 
doing this in v1 when I changed usage of dai->id to dai->driver->id , 
but some how I missed it.

Let me know your thoughts.
-----------------------><---------------------------------------------
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 33e28370..64620ce 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -365,7 +365,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
platform_device *pdev)
         struct device *dev = &pdev->dev;
         const struct of_device_id *match;
         char clk_name[16];
-       int ret, i;
+       int ret, i, dai_id;

         dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
         if (dsp_of_node) {
@@ -412,34 +412,36 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
platform_device *pdev)
                 variant->init(pdev);

         for (i = 0; i < variant->num_dai; i++) {
+               dai_id = variant->dai_driver[i].id;
                 if (variant->num_dai > 1)
                         sprintf(clk_name, "mi2s-osr-clk%d", i);
                 else
                         sprintf(clk_name, "mi2s-osr-clk");

-               drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev,
+               drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
                                                                 clk_name);
-               if (IS_ERR(drvdata->mi2s_osr_clk[i])) {
+               if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
                         dev_err(&pdev->dev,
                                 "%s() error getting mi2s-osr-clk: %ld\n",
                                 __func__,
-                               PTR_ERR(drvdata->mi2s_osr_clk[i]));
+                               PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
                 }
         }

         for (i = 0; i < variant->num_dai; i++) {
+               dai_id = variant->dai_driver[i].id;

                 if (variant->num_dai > 1)
                         sprintf(clk_name, "mi2s-bit-clk%d", i);
                 else
                         sprintf(clk_name, "mi2s-bit-clk");

-               drvdata->mi2s_bit_clk[i] = devm_clk_get(&pdev->dev, 
clk_name);
-               if (IS_ERR(drvdata->mi2s_bit_clk[i])) {
+               drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev, 
clk_name);
+               if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
                         dev_err(&pdev->dev,
                                 "%s() error getting mi2s-bit-clk: %ld\n",
                                 __func__, 
PTR_ERR(drvdata->mi2s_bit_clk[i]));
-                       return PTR_ERR(drvdata->mi2s_bit_clk[i]);
+                       return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
                 }
         }

-----------------------><---------------------------------------------

--srini
>
> -----------------------><---------------------------------------------
> diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
> index 21c6483..2684a4f 100644
> --- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
> +++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
> @@ -8,8 +8,8 @@ Required properties:
>   - clocks		: Must contain an entry for each entry in clock-names.
>   - clock-names		: A list which must include the following entries:
>   				* "ahbix-clk"
> -				* "mi2s-osr-clk"
> -				* "mi2s-bit-clk"
> +				* "mi2s-osr-clk4"
> +				* "mi2s-bit-clk4"
>   			: required clocks for "qcom,lpass-cpu-apq8016"
>   				* "ahbix-clk"
>   				* "mi2s-bit-clk0"
> @@ -42,7 +42,7 @@ Example:
>   lpass@28100000 {
>   	compatible = "qcom,lpass-cpu";
>   	clocks = <&lcc AHBIX_CLK>, <&lcc MI2S_OSR_CLK>, <&lcc MI2S_BIT_CLK>;
> -	clock-names = "ahbix-clk", "mi2s-osr-clk", "mi2s-bit-clk";
> +	clock-names = "ahbix-clk", "mi2s-osr-clk4", "mi2s-bit-clk4";
>   	interrupts = <0 85 1>;
>   	interrupt-names = "lpass-irq-lpaif";
>   	pinctrl-names = "default", "idle";
> diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
> index 5a13366..090984f 100644
> --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
> +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
> @@ -189,8 +189,8 @@
>   					<&lcc MI2S_OSR_CLK>,
>   					<&lcc MI2S_BIT_CLK>;
>   			clock-names = "ahbix-clk",
> -					"mi2s-osr-clk",
> -					"mi2s-bit-clk";
> +					"mi2s-osr-clk4",
> +					"mi2s-bit-clk4";
>   			interrupts = <0 85 1>;
>   			interrupt-names = "lpass-irq-lpaif";
>   			reg = <0x28100000 0x10000>;
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 5053629..7b66e52 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -411,11 +411,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   	if (variant->init)
>   		variant->init(pdev);
>
> -	for (i = 0; i < variant->num_dai; i++) {
> -		if (variant->num_dai > 1)
> -			sprintf(clk_name, "mi2s-osr-clk%d", i);
> -		else
> -			sprintf(clk_name, "mi2s-osr-clk");
> +	for (i = 0; i < LPASS_MAX_MI2S_PORTS; i++) {
> +		sprintf(clk_name, "mi2s-osr-clk%d", i);
>
>   		drvdata->mi2s_osr_clk[i] = devm_clk_get(&pdev->dev,
>   								clk_name);
> @@ -427,19 +424,14 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   		}
>   	}
>
> -	for (i = 0; i < variant->num_dai; i++) {
> -
> -		if (variant->num_dai > 1)
> -			sprintf(clk_name, "mi2s-bit-clk%d", i);
> -		else
> -			sprintf(clk_name, "mi2s-bit-clk");
> +	for (i = 0; i < LPASS_MAX_MI2S_PORTS; i++) {
> +		sprintf(clk_name, "mi2s-bit-clk%d", i);
>
>   		drvdata->mi2s_bit_clk[i] = devm_clk_get(&pdev->dev, clk_name);
>   		if (IS_ERR(drvdata->mi2s_bit_clk[i])) {
>   			dev_err(&pdev->dev,
>   				"%s() error getting mi2s-bit-clk: %ld\n",
>   				__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
> -			return PTR_ERR(drvdata->mi2s_bit_clk[i]);
>   		}
>   	}
> -----------------------><---------------------------------------------
>

^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support
  2015-05-15  5:23     ` Kenneth Westfield
@ 2015-05-15  8:46       ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-15  8:46 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm

Thanks for review,

On 15/05/15 06:23, Kenneth Westfield wrote:
> On Wed, May 13, 2015 at 05:03:06AM -0700, Srinivas Kandagatla wrote:
>> This patch adds apq8016 lpass driver support. APQ8016 has 4 MI2S which
>> can be routed to one internal codec and 2 external codec interfaces.
>>
>> Primary, Secondary, Quaternary I2S can do Rx(playback) and Tertiary and
>> Quaternary can do Tx(capture).
>
>> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
>> index 865205e..9cc5ed7 100644
>> --- a/sound/soc/qcom/Kconfig
>> +++ b/sound/soc/qcom/Kconfig
>> @@ -20,6 +20,12 @@ config SND_SOC_LPASS_IPQ806X
>>   	select SND_SOC_LPASS_CPU
>>   	select SND_SOC_LPASS_PLATFORM
>>
>> +config SND_SOC_LPASS_APQ8016
>> +	tristate
>> +	depends on SND_SOC_QCOM
>> +	select SND_SOC_LPASS_CPU
>> +	select SND_SOC_LPASS_PLATFORM
>
> Continuing from my comments on patch 2/13, should an OF dependency be added
> here as well?
LPASS_CPU and LPASS_PLATFORM already has this dependency, so there is no 
chance that APQ8016 can be selected without OF.

>
>> +
>>   config SND_SOC_STORM
>>   	tristate "ASoC I2S support for Storm boards"
>>   	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
>
>> diff --git a/sound/soc/qcom/lpass-apq8016.c
>> b/sound/soc/qcom/lpass-apq8016.c
>> new file mode 100644
>> index 0000000..5cbf17f0
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-apq8016.c
>
>> +static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int
>> chan)
>> +{
>> +	clear_bit(chan, &drvdata->rdma_ch_bit_map);
>> +
>> +	return 0;
>> +}
>> +
>> +static int apq8016_lpass_init(struct platform_device *pdev)
>> +{
>> +	struct lpass_data *drvdata = platform_get_drvdata(pdev);
>> +	struct device *dev = &pdev->dev;
>> +	int ret;
>> +
>> +	drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
>> +	if (IS_ERR(drvdata->pcnoc_mport_clk)) {
>> +		dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk:
>> %ld\n",
>> +				__func__,
>> PTR_ERR(drvdata->pcnoc_mport_clk));
>> +		return PTR_ERR(drvdata->pcnoc_mport_clk);
>> +	}
>> +
>> +	ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",
>
> Please correct the clock name in the log message ...
>
Yep, will fix it.
>> +				__func__, ret);
>> +		return ret;
>> +	}
>> +
>> +	drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
>> +	if (IS_ERR(drvdata->pcnoc_sway_clk)) {
>> +		dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk:
>> %ld\n",
>> +				__func__,
>> PTR_ERR(drvdata->pcnoc_sway_clk));
>> +		return PTR_ERR(drvdata->pcnoc_sway_clk);
>> +	}
>> +
>> +	ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
>> +	if (ret) {
>> +		dev_err(&pdev->dev, "%s() Error enabling ahbix_clk: %d\n",
>
> ... here too.
>
Sure, I will fix it.

--srini
>> +				__func__, ret);
>> +		return ret;
>> +	}
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support
  2015-05-15  5:23     ` Kenneth Westfield
@ 2015-05-15  8:47       ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-15  8:47 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 15/05/15 06:23, Kenneth Westfield wrote:
> On Wed, May 13, 2015 at 05:03:14AM -0700, Srinivas Kandagatla wrote:
>> This patch adds apq8016 machine driver support. This patch was tested on
>> two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
>> features.
>
>> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
>> index 9cc5ed7..e71b0f2 100644
>> --- a/sound/soc/qcom/Kconfig
>> +++ b/sound/soc/qcom/Kconfig
>> @@ -34,3 +34,12 @@ config SND_SOC_STORM
>>   	help
>>             Say Y or M if you want add support for SoC audio on the
>>             Qualcomm Technologies IPQ806X-based Storm board.
>> +
>> +config SND_SOC_APQ8016_SBC
>> +	tristate "SoC Audio support for APQ8016 SBC platforms"
>> +	depends on SND_SOC_QCOM || ARCH_QCOM || COMPILE_TEST
>
> I believe this should be:
>          depends on (SND_SOC_QCOM && ARCH_QCOM) || COMPILE_TEST
>
Yep , I will fix it.
>> +	select SND_SOC_LPASS_APQ8016
>> +	help
>> +          Support for Qualcomm Technologies LPASS audio block in
>> +          APQ8016 SOC-based systems.
>> +          Say Y if you want to use audio devices on MI2S
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-15  5:23     ` Kenneth Westfield
@ 2015-05-15  8:48       ` Srinivas Kandagatla
  0 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-15  8:48 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Liam Girdwood, Jaroslav Kysela,
	Takashi Iwai, devicetree, linux-kernel, alsa-devel,
	linux-arm-msm



On 15/05/15 06:23, Kenneth Westfield wrote:
> On Wed, May 13, 2015 at 05:00:26AM -0700, Srinivas Kandagatla wrote:
>> This patch tries to make the lpass driver more generic by moving the
>> ipq806x specific bits out of the cpu and platform driver, also allows the
>> SOC specific drivers to add the correct register offsets.
>>
>> This patch also renames the register definition header file into more
>> generic header file.
>
>> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
>> index 05b9840..865205e 100644
>> --- a/sound/soc/qcom/Kconfig
>> +++ b/sound/soc/qcom/Kconfig
>
>> @@ -14,11 +14,16 @@ config SND_SOC_LPASS_PLATFORM
>>   	depends on SND_SOC_QCOM && OF
>>   	select REGMAP_MMIO
>>
>> +config SND_SOC_LPASS_IPQ806X
>> +	tristate
>> +	depends on SND_SOC_QCOM
>> +	select SND_SOC_LPASS_CPU
>> +	select SND_SOC_LPASS_PLATFORM
>
> Based on moving the of_device_id table from lpass-cpu.c to
> lpass-ipq806x.c, shouldn't the OF dependency follow to the
> SND_SOC_LPASS_IPQ806X config (and not SND_SOC_LPASS_CPU)?
>
>> +
>>   config SND_SOC_STORM
>>   	tristate "ASoC I2S support for Storm boards"
>>   	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
>> -	select SND_SOC_LPASS_CPU
>> -	select SND_SOC_LPASS_PLATFORM
>> +	select SND_SOC_LPASS_IPQ806X
>>   	select SND_SOC_MAX98357A
>>   	help
>>             Say Y or M if you want add support for SoC audio on the
>
>> diff --git a/sound/soc/qcom/lpass-ipq806x.c
>> b/sound/soc/qcom/lpass-ipq806x.c
>> new file mode 100644
>> index 0000000..d1f698c
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-ipq806x.c
>
>> +static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
>> +	.driver	= {
>> +		.name		= "lpass-cpu",
>> +		.of_match_table	=
>> of_match_ptr(ipq806x_lpass_cpu_device_id),
>> +	},
>> +	.probe	= asoc_qcom_lpass_cpu_platform_probe,
>> +	.remove	= asoc_qcom_lpass_cpu_platform_remove,
>> +};
>> +module_platform_driver(ipq801x_lpass_cpu_platform_driver);
>
> Patch below fixes the above typo (which breaks compilation):
>

Oops, will fix it.

> -----------------------><---------------------------------------------
> diff --git a/sound/soc/qcom/lpass-ipq806x.c
> b/sound/soc/qcom/lpass-ipq806x.c
> index ad1d67a..2eab828 100644
> --- a/sound/soc/qcom/lpass-ipq806x.c
> +++ b/sound/soc/qcom/lpass-ipq806x.c
> @@ -103,7 +103,7 @@ static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
>          .probe  = asoc_qcom_lpass_cpu_platform_probe,
>          .remove = asoc_qcom_lpass_cpu_platform_remove,
>   };
> -module_platform_driver(ipq801x_lpass_cpu_platform_driver);
> +module_platform_driver(ipq806x_lpass_cpu_platform_driver);
>
>   MODULE_DESCRIPTION("QTi LPASS CPU Driver");
>   MODULE_LICENSE("GPL v2");
> -----------------------><---------------------------------------------
>
>> +
>> +MODULE_DESCRIPTION("QTi LPASS CPU Driver");
>> +MODULE_LICENSE("GPL v2");
>

^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio
  2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                   ` (15 preceding siblings ...)
  2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
@ 2015-05-16 12:31 ` Srinivas Kandagatla
  2015-05-16 12:32   ` [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
                     ` (14 more replies)
  16 siblings, 15 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:31 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

Thankyou for reviewing the v1 patches, here is the v2 patchset after
incorporating review comments and testing on Storm Board.
This patchset adds apq8016 audio support into lpass driver. Existing
Lpass driver can not be used as-it-is for apq8016 as it contains code
specific to ipq806x. Also the driver only supports single i2s port,
single dma channel and single bitclk control.

APQ8016 has 4 MI2S( Primary, Secondary, Tertiary, Quaternary) which can be routed
to internal wcd codec or external codecs. This routing is controlled by 2 mux
registers.

This patch series firstly re-organizes the lpass driver such that the SOC
specific bits are moved away from the driver. And secondly the SOC specifics
are now passed as lpass variant data which would include various register
offsets, dma channel allocations and SOC specific clock handling.

Finally the last few patchs add apq8016 lpass and machine driver.

All these patches are tested for HDMI audio via adv7533 bridge and Analog audio
on APQ8016-SBC, msm8916-mtp boards and Kenneth tested this patchset on
ipq806x Storm board too.

--srini

Changes since v1(https://lwn.net/Articles/644266/)
 - Fixed Kconfig dependencies spotted by Kenneth
 - Fixed compilation error on ipq806x spotted by Kenneth
 - Fixed clk error messages spotted by Kenneth

Changes since RFC(https://lwn.net/Articles/642661/)
 - droped cleanup patches, as they are already applied by Mark.
 - prefixed shared functions with asoc_qcom_* as suggested by Kenneth
 - made LPASS driver depended on OF.
 - removed ipq806x specific bits from ipaif_reg.h
 - removed no_osr clk flag as suggested by Mark and Kenneth
 - fixed irq return values spotted by Kenneth
 - renamed the machine file to apq8016-sbc.c as suggested by Kenneth.
 - use dai->driver->id instead of dai->id as it breaks on Storm board.


Srinivas Kandagatla (13):
  ASoC: qcom: make lpass driver depend on OF
  ASoC: qcom: move ipq806x specific bits out of lpass driver.
  ASoC: qcom: remove hardcoded i2s port number
  ASoC: qcom: remove hardcoded dma channel
  ASoC: qcom: support bitclk and osrclk per i2s port
  ASoC: qcom: make osr clock optional
  ASoC: qcom: add dma channel control offset to variant data
  ASoC: qcom: Add ability to handle interrupts per dma channel
  ASoC: qcom: add bit map to track static dma channel allocations
  ASoC: qcom: Add apq8016 lpass driver support
  ASoC: qcom: add apq8016 sound card support
  ASoC: qcom: Document apq8016 bindings.
  ASoC: qcom: document apq8016 sbc machine driver bindings

 .../devicetree/bindings/sound/qcom,apq8016-sbc.txt |  61 ++++++
 .../devicetree/bindings/sound/qcom,lpass-cpu.txt   |  13 +-
 include/dt-bindings/sound/apq8016-lpass.h          |   9 +
 sound/soc/qcom/Kconfig                             |  28 ++-
 sound/soc/qcom/Makefile                            |   6 +
 sound/soc/qcom/apq8016_sbc.c                       | 215 ++++++++++++++++++
 sound/soc/qcom/lpass-apq8016.c                     | 242 +++++++++++++++++++++
 sound/soc/qcom/lpass-cpu.c                         | 230 +++++++++++---------
 sound/soc/qcom/lpass-ipq806x.c                     | 109 ++++++++++
 sound/soc/qcom/lpass-lpaif-ipq806x.h               | 172 ---------------
 sound/soc/qcom/lpass-lpaif-reg.h                   | 126 +++++++++++
 sound/soc/qcom/lpass-platform.c                    | 196 +++++++++++------
 sound/soc/qcom/lpass.h                             |  51 ++++-
 13 files changed, 1109 insertions(+), 349 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
 create mode 100644 include/dt-bindings/sound/apq8016-lpass.h
 create mode 100644 sound/soc/qcom/apq8016_sbc.c
 create mode 100644 sound/soc/qcom/lpass-apq8016.c
 create mode 100644 sound/soc/qcom/lpass-ipq806x.c
 delete mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
 create mode 100644 sound/soc/qcom/lpass-lpaif-reg.h

-- 
1.9.1


^ permalink raw reply	[flat|nested] 88+ messages in thread

* [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-21 20:10     ` Mark Brown
  2015-05-16 12:32   ` [PATCH v2 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
                     ` (13 subsequent siblings)
  14 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

lpass driver only support DT so make this explicit in the kconfig.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 5f58e4f..05b9840 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -6,12 +6,12 @@ config SND_SOC_QCOM
 
 config SND_SOC_LPASS_CPU
 	tristate
-	depends on SND_SOC_QCOM
+	depends on SND_SOC_QCOM && OF
 	select REGMAP_MMIO
 
 config SND_SOC_LPASS_PLATFORM
 	tristate
-	depends on SND_SOC_QCOM
+	depends on SND_SOC_QCOM && OF
 	select REGMAP_MMIO
 
 config SND_SOC_STORM
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
  2015-05-16 12:32   ` [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-21 20:11     ` Mark Brown
  2015-05-16 12:32   ` [PATCH v2 03/13] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
                     ` (12 subsequent siblings)
  14 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch tries to make the lpass driver more generic by moving the
ipq806x specific bits out of the cpu and platform driver, also allows the
SOC specific drivers to add the correct register offsets.

This patch also renames the register definition header file into more
generic header file.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig               |   9 +-
 sound/soc/qcom/Makefile              |   2 +
 sound/soc/qcom/lpass-cpu.c           | 157 ++++++++++++++++----------------
 sound/soc/qcom/lpass-ipq806x.c       |  96 +++++++++++++++++++
 sound/soc/qcom/lpass-lpaif-ipq806x.h | 172 -----------------------------------
 sound/soc/qcom/lpass-lpaif-reg.h     | 126 +++++++++++++++++++++++++
 sound/soc/qcom/lpass-platform.c      |  49 ++++++----
 sound/soc/qcom/lpass.h               |  28 ++++++
 8 files changed, 364 insertions(+), 275 deletions(-)
 create mode 100644 sound/soc/qcom/lpass-ipq806x.c
 delete mode 100644 sound/soc/qcom/lpass-lpaif-ipq806x.h
 create mode 100644 sound/soc/qcom/lpass-lpaif-reg.h

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 05b9840..865205e 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -14,11 +14,16 @@ config SND_SOC_LPASS_PLATFORM
 	depends on SND_SOC_QCOM && OF
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_IPQ806X
+	tristate
+	depends on SND_SOC_QCOM
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
-	select SND_SOC_LPASS_CPU
-	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_IPQ806X
 	select SND_SOC_MAX98357A
 	help
           Say Y or M if you want add support for SoC audio on the
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index c5ce96c..f8aab91 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,9 +1,11 @@
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
+snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
+obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 
 # Machine
 snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 4246970..2c20927 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -17,14 +17,14 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
 #include <sound/soc-dai.h>
-
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
@@ -138,7 +138,9 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), regval);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S),
+			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -162,7 +164,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -177,7 +180,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+			LPAIF_I2SCTL_REG(drvdata->variant, LPAIF_I2S_PORT_MI2S),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -197,7 +200,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant,
+				LPAIF_I2S_PORT_MI2S),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -208,7 +212,8 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S),
+				LPAIF_I2SCTL_REG(drvdata->variant,
+				LPAIF_I2S_PORT_MI2S),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -220,7 +225,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
+struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
 	.set_sysclk	= lpass_cpu_daiops_set_sysclk,
 	.startup	= lpass_cpu_daiops_startup,
 	.shutdown	= lpass_cpu_daiops_shutdown,
@@ -229,41 +234,24 @@ static struct snd_soc_dai_ops lpass_cpu_dai_ops = {
 	.prepare	= lpass_cpu_daiops_prepare,
 	.trigger	= lpass_cpu_daiops_trigger,
 };
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_ops);
 
-static int lpass_cpu_dai_probe(struct snd_soc_dai *dai)
+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant,
+			   LPAIF_I2S_PORT_MI2S), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
 
 	return ret;
 }
-
-static struct snd_soc_dai_driver lpass_cpu_dai_driver = {
-	.playback = {
-		.stream_name	= "lpass-cpu-playback",
-		.formats	= SNDRV_PCM_FMTBIT_S16 |
-					SNDRV_PCM_FMTBIT_S24 |
-					SNDRV_PCM_FMTBIT_S32,
-		.rates		= SNDRV_PCM_RATE_8000 |
-					SNDRV_PCM_RATE_16000 |
-					SNDRV_PCM_RATE_32000 |
-					SNDRV_PCM_RATE_48000 |
-					SNDRV_PCM_RATE_96000,
-		.rate_min	= 8000,
-		.rate_max	= 96000,
-		.channels_min	= 1,
-		.channels_max	= 8,
-	},
-	.probe	= &lpass_cpu_dai_probe,
-	.ops    = &lpass_cpu_dai_ops,
-};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe);
 
 static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 	.name = "lpass-cpu",
@@ -271,27 +259,29 @@ static const struct snd_soc_component_driver lpass_cpu_comp_driver = {
 
 static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-		if (reg == LPAIF_I2SCTL_REG(i))
+	for (i = 0; i < v->i2s_ports; ++i)
+		if (reg == LPAIF_I2SCTL_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-		if (reg == LPAIF_IRQEN_REG(i))
+	for (i = 0; i < v->irq_ports; ++i) {
+		if (reg == LPAIF_IRQEN_REG(v, i))
 			return true;
-		if (reg == LPAIF_IRQCLEAR_REG(i))
+		if (reg == LPAIF_IRQCLEAR_REG(v, i))
 			return true;
 	}
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-		if (reg == LPAIF_RDMACTL_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_RDMACTL_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABASE_REG(i))
+		if (reg == LPAIF_RDMABASE_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABUFF_REG(i))
+		if (reg == LPAIF_RDMABUFF_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMAPER_REG(i))
+		if (reg == LPAIF_RDMAPER_REG(v, i))
 			return true;
 	}
 
@@ -300,29 +290,31 @@ static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_I2S_PORT_NUM; ++i)
-		if (reg == LPAIF_I2SCTL_REG(i))
+	for (i = 0; i < v->i2s_ports; ++i)
+		if (reg == LPAIF_I2SCTL_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i) {
-		if (reg == LPAIF_IRQEN_REG(i))
+	for (i = 0; i < v->irq_ports; ++i) {
+		if (reg == LPAIF_IRQEN_REG(v, i))
 			return true;
-		if (reg == LPAIF_IRQSTAT_REG(i))
+		if (reg == LPAIF_IRQSTAT_REG(v, i))
 			return true;
 	}
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i) {
-		if (reg == LPAIF_RDMACTL_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_RDMACTL_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABASE_REG(i))
+		if (reg == LPAIF_RDMABASE_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMABUFF_REG(i))
+		if (reg == LPAIF_RDMABUFF_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMACURR_REG(i))
+		if (reg == LPAIF_RDMACURR_REG(v, i))
 			return true;
-		if (reg == LPAIF_RDMAPER_REG(i))
+		if (reg == LPAIF_RDMAPER_REG(v, i))
 			return true;
 	}
 
@@ -331,35 +323,39 @@ static bool lpass_cpu_regmap_readable(struct device *dev, unsigned int reg)
 
 static bool lpass_cpu_regmap_volatile(struct device *dev, unsigned int reg)
 {
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
 	int i;
 
-	for (i = 0; i < LPAIF_IRQ_PORT_NUM; ++i)
-		if (reg == LPAIF_IRQSTAT_REG(i))
+	for (i = 0; i < v->irq_ports; ++i)
+		if (reg == LPAIF_IRQSTAT_REG(v, i))
 			return true;
 
-	for (i = 0; i < LPAIF_RDMA_CHAN_NUM; ++i)
-		if (reg == LPAIF_RDMACURR_REG(i))
+	for (i = 0; i < v->rdma_channels; ++i)
+		if (reg == LPAIF_RDMACURR_REG(v, i))
 			return true;
 
 	return false;
 }
 
-static const struct regmap_config lpass_cpu_regmap_config = {
+static struct regmap_config lpass_cpu_regmap_config = {
 	.reg_bits = 32,
 	.reg_stride = 4,
 	.val_bits = 32,
-	.max_register = LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MAX),
 	.writeable_reg = lpass_cpu_regmap_writeable,
 	.readable_reg = lpass_cpu_regmap_readable,
 	.volatile_reg = lpass_cpu_regmap_volatile,
 	.cache_type = REGCACHE_FLAT,
 };
 
-static int lpass_cpu_platform_probe(struct platform_device *pdev)
+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata;
 	struct device_node *dsp_of_node;
 	struct resource *res;
+	struct lpass_variant *variant;
+	struct device *dev = &pdev->dev;
+	const struct of_device_id *match;
 	int ret;
 
 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
@@ -375,6 +371,13 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return -ENOMEM;
 	platform_set_drvdata(pdev, drvdata);
 
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data)
+		return -EINVAL;
+
+	drvdata->variant = (struct lpass_variant *)match->data;
+	variant = drvdata->variant;
+
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
 
 	drvdata->lpaif = devm_ioremap_resource(&pdev->dev, res);
@@ -385,6 +388,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return PTR_ERR((void const __force *)drvdata->lpaif);
 	}
 
+	lpass_cpu_regmap_config.max_register = LPAIF_RDMAPER_REG(variant,
+						variant->rdma_channels);
+
 	drvdata->lpaif_map = devm_regmap_init_mmio(&pdev->dev, drvdata->lpaif,
 			&lpass_cpu_regmap_config);
 	if (IS_ERR(drvdata->lpaif_map)) {
@@ -393,6 +399,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 		return PTR_ERR(drvdata->lpaif_map);
 	}
 
+	if (variant->init)
+		variant->init(pdev);
+
 	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
 	if (IS_ERR(drvdata->mi2s_osr_clk)) {
 		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
@@ -431,7 +440,9 @@ static int lpass_cpu_platform_probe(struct platform_device *pdev)
 	}
 
 	ret = devm_snd_soc_register_component(&pdev->dev,
-			&lpass_cpu_comp_driver, &lpass_cpu_dai_driver, 1);
+					      &lpass_cpu_comp_driver,
+					      variant->dai_driver,
+					      variant->num_dai);
 	if (ret) {
 		dev_err(&pdev->dev, "%s() error registering cpu driver: %d\n",
 				__func__, ret);
@@ -451,33 +462,17 @@ err_clk:
 	clk_disable_unprepare(drvdata->ahbix_clk);
 	return ret;
 }
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
 
-static int lpass_cpu_platform_remove(struct platform_device *pdev)
+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
 
+	if (drvdata->variant->exit)
+		drvdata->variant->exit(pdev);
+
 	clk_disable_unprepare(drvdata->ahbix_clk);
 
 	return 0;
 }
-
-#ifdef CONFIG_OF
-static const struct of_device_id lpass_cpu_device_id[] = {
-	{ .compatible = "qcom,lpass-cpu" },
-	{}
-};
-MODULE_DEVICE_TABLE(of, lpass_cpu_device_id);
-#endif
-
-static struct platform_driver lpass_cpu_platform_driver = {
-	.driver	= {
-		.name		= "lpass-cpu",
-		.of_match_table	= of_match_ptr(lpass_cpu_device_id),
-	},
-	.probe	= lpass_cpu_platform_probe,
-	.remove	= lpass_cpu_platform_remove,
-};
-module_platform_driver(lpass_cpu_platform_driver);
-
-MODULE_DESCRIPTION("QTi LPASS CPU Driver");
-MODULE_LICENSE("GPL v2");
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_remove);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
new file mode 100644
index 0000000..4a0e3fb
--- /dev/null
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ *
+ * lpass-ipq806x.c -- ALSA SoC CPU DAI driver for QTi LPASS
+ * Splited out the IPQ8064 soc specific from lpass-cpu.c
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+enum lpaif_i2s_ports {
+	IPQ806X_LPAIF_I2S_PORT_CODEC_SPK,
+	IPQ806X_LPAIF_I2S_PORT_CODEC_MIC,
+	IPQ806X_LPAIF_I2S_PORT_SEC_SPK,
+	IPQ806X_LPAIF_I2S_PORT_SEC_MIC,
+	IPQ806X_LPAIF_I2S_PORT_MI2S,
+};
+
+enum lpaif_dma_channels {
+	IPQ806X_LPAIF_RDMA_CHAN_MI2S,
+	IPQ806X_LPAIF_RDMA_CHAN_PCM0,
+	IPQ806X_LPAIF_RDMA_CHAN_PCM1,
+};
+
+static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
+	.playback = {
+		.stream_name	= "lpass-cpu-playback",
+		.formats	= SNDRV_PCM_FMTBIT_S16 |
+					SNDRV_PCM_FMTBIT_S24 |
+					SNDRV_PCM_FMTBIT_S32,
+		.rates		= SNDRV_PCM_RATE_8000 |
+					SNDRV_PCM_RATE_16000 |
+					SNDRV_PCM_RATE_32000 |
+					SNDRV_PCM_RATE_48000 |
+					SNDRV_PCM_RATE_96000,
+		.rate_min	= 8000,
+		.rate_max	= 96000,
+		.channels_min	= 1,
+		.channels_max	= 8,
+	},
+	.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+	.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+};
+
+struct lpass_variant ipq806x_data = {
+	.i2sctrl_reg_base	= 0x0010,
+	.i2sctrl_reg_stride	= 0x04,
+	.i2s_ports		= 5,
+	.irq_reg_base		= 0x3000,
+	.irq_reg_stride		= 0x1000,
+	.irq_ports		= 3,
+	.rdma_reg_base		= 0x6000,
+	.rdma_reg_stride	= 0x1000,
+	.rdma_channels		= 4,
+	.dai_driver		= &ipq806x_lpass_cpu_dai_driver,
+	.num_dai		= 1,
+};
+
+static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
+	{ .compatible = "qcom,lpass-cpu", .data = &ipq806x_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, ipq806x_lpass_cpu_device_id);
+
+static struct platform_driver ipq806x_lpass_cpu_platform_driver = {
+	.driver	= {
+		.name		= "lpass-cpu",
+		.of_match_table	= of_match_ptr(ipq806x_lpass_cpu_device_id),
+	},
+	.probe	= asoc_qcom_lpass_cpu_platform_probe,
+	.remove	= asoc_qcom_lpass_cpu_platform_remove,
+};
+module_platform_driver(ipq806x_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("QTi LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-lpaif-ipq806x.h b/sound/soc/qcom/lpass-lpaif-ipq806x.h
deleted file mode 100644
index dc423b8..0000000
--- a/sound/soc/qcom/lpass-lpaif-ipq806x.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
- *
- * 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.
- *
- * lpass-lpaif-ipq806x.h -- Definitions for the QTi LPAIF in the ipq806x LPASS
- */
-
-#ifndef __LPASS_LPAIF_H__
-#define __LPASS_LPAIF_H__
-
-#define LPAIF_BANK_OFFSET		0x1000
-
-/* LPAIF I2S */
-
-#define LPAIF_I2SCTL_REG_BASE		0x0010
-#define LPAIF_I2SCTL_REG_STRIDE		0x4
-#define LPAIF_I2SCTL_REG_ADDR(addr, port) \
-	(LPAIF_I2SCTL_REG_BASE + (addr) + (LPAIF_I2SCTL_REG_STRIDE * (port)))
-
-enum lpaif_i2s_ports {
-	LPAIF_I2S_PORT_MIN		= 0,
-
-	LPAIF_I2S_PORT_CODEC_SPK	= 0,
-	LPAIF_I2S_PORT_CODEC_MIC	= 1,
-	LPAIF_I2S_PORT_SEC_SPK		= 2,
-	LPAIF_I2S_PORT_SEC_MIC		= 3,
-	LPAIF_I2S_PORT_MI2S		= 4,
-
-	LPAIF_I2S_PORT_MAX		= 4,
-	LPAIF_I2S_PORT_NUM		= 5,
-};
-
-#define LPAIF_I2SCTL_REG(port)		LPAIF_I2SCTL_REG_ADDR(0x0, (port))
-
-#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
-#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
-#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-
-#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
-#define LPAIF_I2SCTL_SPKEN_SHIFT	14
-#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
-#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
-#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
-#define LPAIF_I2SCTL_SPKMODE_NONE	(0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD0	(1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD1	(2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD2	(3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_SD3	(4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD01	(5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_QUAD23	(6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_6CH	(7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-#define LPAIF_I2SCTL_SPKMODE_8CH	(8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
-
-#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
-#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
-#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-
-#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
-#define LPAIF_I2SCTL_WSSRC_SHIFT	2
-#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
-#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
-
-#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
-#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
-#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-
-/* LPAIF IRQ */
-
-#define LPAIF_IRQ_REG_BASE		0x3000
-#define LPAIF_IRQ_REG_STRIDE		0x1000
-#define LPAIF_IRQ_REG_ADDR(addr, port) \
-	(LPAIF_IRQ_REG_BASE + (addr) + (LPAIF_IRQ_REG_STRIDE * (port)))
-
-enum lpaif_irq_ports {
-	LPAIF_IRQ_PORT_MIN		= 0,
-
-	LPAIF_IRQ_PORT_HOST		= 0,
-	LPAIF_IRQ_PORT_ADSP		= 1,
-
-	LPAIF_IRQ_PORT_MAX		= 2,
-	LPAIF_IRQ_PORT_NUM		= 3,
-};
-
-#define LPAIF_IRQEN_REG(port)		LPAIF_IRQ_REG_ADDR(0x0, (port))
-#define LPAIF_IRQSTAT_REG(port)		LPAIF_IRQ_REG_ADDR(0x4, (port))
-#define LPAIF_IRQCLEAR_REG(port)	LPAIF_IRQ_REG_ADDR(0xC, (port))
-
-#define LPAIF_IRQ_BITSTRIDE		3
-#define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_XRUN(chan)		(2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-#define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
-
-/* LPAIF DMA */
-
-#define LPAIF_RDMA_REG_BASE		0x6000
-#define LPAIF_RDMA_REG_STRIDE		0x1000
-#define LPAIF_RDMA_REG_ADDR(addr, chan) \
-	(LPAIF_RDMA_REG_BASE + (addr) + (LPAIF_RDMA_REG_STRIDE * (chan)))
-
-enum lpaif_dma_channels {
-	LPAIF_RDMA_CHAN_MIN		= 0,
-
-	LPAIF_RDMA_CHAN_MI2S		= 0,
-	LPAIF_RDMA_CHAN_PCM0		= 1,
-	LPAIF_RDMA_CHAN_PCM1		= 2,
-
-	LPAIF_RDMA_CHAN_MAX		= 4,
-	LPAIF_RDMA_CHAN_NUM		= 5,
-};
-
-#define LPAIF_RDMACTL_REG(chan)		LPAIF_RDMA_REG_ADDR(0x00, (chan))
-#define LPAIF_RDMABASE_REG(chan)	LPAIF_RDMA_REG_ADDR(0x04, (chan))
-#define	LPAIF_RDMABUFF_REG(chan)	LPAIF_RDMA_REG_ADDR(0x08, (chan))
-#define LPAIF_RDMACURR_REG(chan)	LPAIF_RDMA_REG_ADDR(0x0C, (chan))
-#define	LPAIF_RDMAPER_REG(chan)		LPAIF_RDMA_REG_ADDR(0x10, (chan))
-
-#define LPAIF_RDMACTL_BURSTEN_MASK	0x800
-#define LPAIF_RDMACTL_BURSTEN_SHIFT	11
-#define LPAIF_RDMACTL_BURSTEN_SINGLE	(0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-#define LPAIF_RDMACTL_BURSTEN_INCR4	(1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
-
-#define LPAIF_RDMACTL_WPSCNT_MASK	0x700
-#define LPAIF_RDMACTL_WPSCNT_SHIFT	8
-#define LPAIF_RDMACTL_WPSCNT_ONE	(0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_TWO	(1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_THREE	(2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_FOUR	(3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_SIX	(5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-#define LPAIF_RDMACTL_WPSCNT_EIGHT	(7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
-
-#define LPAIF_RDMACTL_AUDINTF_MASK	0x0F0
-#define LPAIF_RDMACTL_AUDINTF_SHIFT	4
-#define LPAIF_RDMACTL_AUDINTF_NONE	(0 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_CODEC	(1 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_PCM	(2 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_I2S	(3 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_MI2S	(4 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_HDMI	(5 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-#define LPAIF_RDMACTL_AUDINTF_SEC_PCM	(7 << LPAIF_RDMACTL_AUDINTF_SHIFT)
-
-#define LPAIF_RDMACTL_FIFOWM_MASK	0x00E
-#define LPAIF_RDMACTL_FIFOWM_SHIFT	1
-#define LPAIF_RDMACTL_FIFOWM_1		(0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_2		(1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_3		(2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_4		(3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_5		(4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_6		(5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_7		(6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-#define LPAIF_RDMACTL_FIFOWM_8		(7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
-
-#define LPAIF_RDMACTL_ENABLE_MASK	0x1
-#define LPAIF_RDMACTL_ENABLE_SHIFT	0
-#define LPAIF_RDMACTL_ENABLE_OFF	(0 << LPAIF_RDMACTL_ENABLE_SHIFT)
-#define LPAIF_RDMACTL_ENABLE_ON		(1 << LPAIF_RDMACTL_ENABLE_SHIFT)
-
-#endif /* __LPASS_LPAIF_H__ */
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
new file mode 100644
index 0000000..95e22f1
--- /dev/null
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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 __LPASS_LPAIF_REG_H__
+#define __LPASS_LPAIF_REG_H__
+
+/* LPAIF I2S */
+
+#define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
+	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
+
+#define LPAIF_I2SCTL_REG(v, port)	LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
+#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
+#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
+#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
+
+#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
+#define LPAIF_I2SCTL_SPKEN_SHIFT	14
+#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
+#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
+#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
+#define LPAIF_I2SCTL_SPKMODE_NONE	(0 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD0	(1 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD1	(2 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD2	(3 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_SD3	(4 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD01	(5 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_QUAD23	(6 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_6CH	(7 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE_8CH	(8 << LPAIF_I2SCTL_SPKMODE_SHIFT)
+
+#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
+#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
+#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+
+#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
+#define LPAIF_I2SCTL_WSSRC_SHIFT	2
+#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
+#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
+
+#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
+#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
+#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+
+/* LPAIF IRQ */
+#define LPAIF_IRQ_REG_ADDR(v, addr, port) \
+	(v->irq_reg_base + (addr) + v->irq_reg_stride * (port))
+
+#define LPAIF_IRQ_PORT_HOST		0
+
+#define LPAIF_IRQEN_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x0, (port))
+#define LPAIF_IRQSTAT_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
+#define LPAIF_IRQCLEAR_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
+
+#define LPAIF_IRQ_BITSTRIDE		3
+
+#define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_XRUN(chan)		(2 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+#define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+
+/* LPAIF DMA */
+
+#define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
+	(v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
+
+#define LPAIF_RDMACTL_AUDINTF(id)	(id << LPAIF_RDMACTL_AUDINTF_SHIFT)
+
+#define LPAIF_RDMACTL_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x00, (chan))
+#define LPAIF_RDMABASE_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x04, (chan))
+#define	LPAIF_RDMABUFF_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x08, (chan))
+#define LPAIF_RDMACURR_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x0C, (chan))
+#define	LPAIF_RDMAPER_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x10, (chan))
+#define	LPAIF_RDMAPERCNT_REG(v, chan)	LPAIF_RDMA_REG_ADDR(v, 0x14, (chan))
+
+#define LPAIF_RDMACTL_BURSTEN_MASK	0x800
+#define LPAIF_RDMACTL_BURSTEN_SHIFT	11
+#define LPAIF_RDMACTL_BURSTEN_SINGLE	(0 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+#define LPAIF_RDMACTL_BURSTEN_INCR4	(1 << LPAIF_RDMACTL_BURSTEN_SHIFT)
+
+#define LPAIF_RDMACTL_WPSCNT_MASK	0x700
+#define LPAIF_RDMACTL_WPSCNT_SHIFT	8
+#define LPAIF_RDMACTL_WPSCNT_ONE	(0 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_TWO	(1 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_THREE	(2 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_FOUR	(3 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_SIX	(5 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+#define LPAIF_RDMACTL_WPSCNT_EIGHT	(7 << LPAIF_RDMACTL_WPSCNT_SHIFT)
+
+#define LPAIF_RDMACTL_AUDINTF_MASK	0x0F0
+#define LPAIF_RDMACTL_AUDINTF_SHIFT	4
+
+#define LPAIF_RDMACTL_FIFOWM_MASK	0x00E
+#define LPAIF_RDMACTL_FIFOWM_SHIFT	1
+#define LPAIF_RDMACTL_FIFOWM_1		(0 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_2		(1 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_3		(2 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_4		(3 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_5		(4 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_6		(5 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_7		(6 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+#define LPAIF_RDMACTL_FIFOWM_8		(7 << LPAIF_RDMACTL_FIFOWM_SHIFT)
+
+#define LPAIF_RDMACTL_ENABLE_MASK	0x1
+#define LPAIF_RDMACTL_ENABLE_SHIFT	0
+#define LPAIF_RDMACTL_ENABLE_OFF	(0 << LPAIF_RDMACTL_ENABLE_SHIFT)
+#define LPAIF_RDMACTL_ENABLE_ON		(1 << LPAIF_RDMACTL_ENABLE_SHIFT)
+
+#endif /* __LPASS_LPAIF_REG_H__ */
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index ffc0928..a38e7ec 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -21,7 +21,7 @@
 #include <sound/pcm_params.h>
 #include <linux/regmap.h>
 #include <sound/soc.h>
-#include "lpass-lpaif-ipq806x.h"
+#include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
@@ -80,6 +80,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	snd_pcm_format_t format = params_format(params);
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
@@ -150,7 +151,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), regval);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), regval);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -165,10 +166,11 @@ static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -182,10 +184,11 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -194,7 +197,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABUFF_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABUFF_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -203,7 +206,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMAPER_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMAPER_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -212,7 +215,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -229,6 +232,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	switch (cmd) {
@@ -237,7 +241,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		/* clear status before enabling interrupts */
 		ret = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -246,7 +250,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
 		if (ret) {
@@ -256,7 +260,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_ON);
 		if (ret) {
@@ -269,7 +273,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_OFF);
 		if (ret) {
@@ -279,7 +283,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
@@ -298,11 +302,13 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
 	int ret;
 
 	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(LPAIF_RDMA_CHAN_MI2S), &base_addr);
+			 LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			 &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
 				__func__, ret);
@@ -310,7 +316,8 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	}
 
 	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_RDMACURR_REG(LPAIF_RDMA_CHAN_MI2S), &curr_addr);
+			 LPAIF_RDMACURR_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			 &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
 				__func__, ret);
@@ -347,12 +354,13 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
 	int rv;
 
 	rv = regmap_read(drvdata->lpaif_map,
-			LPAIF_IRQSTAT_REG(LPAIF_IRQ_PORT_HOST), &interrupts);
+			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
 	if (rv) {
 		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
 				__func__, rv);
@@ -362,7 +370,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -375,7 +383,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -389,7 +397,7 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
 		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(LPAIF_IRQ_PORT_HOST),
+				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
 				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
@@ -444,6 +452,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
@@ -464,14 +473,14 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_IRQEN_REG(LPAIF_IRQ_PORT_HOST), 0);
+			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 				__func__, ret);
 		return ret;
 	}
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 5c99b3d..fa00be4 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -43,9 +43,37 @@ struct lpass_data {
 
 	/* interrupts from the low-power audio interface (LPAIF) */
 	int lpaif_irq;
+
+	/* SOC specific variations in the LPASS IP integration */
+	struct lpass_variant *variant;
+};
+
+/* Vairant data per each SOC */
+struct lpass_variant {
+	u32	i2sctrl_reg_base;
+	u32	i2sctrl_reg_stride;
+	u32	i2s_ports;
+	u32	irq_reg_base;
+	u32	irq_reg_stride;
+	u32	irq_ports;
+	u32	rdma_reg_base;
+	u32	rdma_reg_stride;
+	u32	rdma_channels;
+
+	/* SOC specific intialization like clocks */
+	int (*init)(struct platform_device *pdev);
+	int (*exit)(struct platform_device *pdev);
+
+	/* SOC specific dais */
+	struct snd_soc_dai_driver *dai_driver;
+	int num_dai;
 };
 
 /* register the platform driver from the CPU DAI driver */
 int asoc_qcom_lpass_platform_register(struct platform_device *);
+int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
+int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
+int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
+extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
 
 #endif /* __LPASS_H__ */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 03/13] ASoC: qcom: remove hardcoded i2s port number
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
  2015-05-16 12:32   ` [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
  2015-05-16 12:32   ` [PATCH v2 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-16 12:32   ` [PATCH v2 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
                     ` (11 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch attempts to remove the hardcoded i2s port number in lpass
driver. Now the the port number comes from the dai id field.

This will allow other SOCs to use different port numbers on the lpass
driver.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c     | 16 +++++++---------
 sound/soc/qcom/lpass-ipq806x.c |  1 +
 2 files changed, 8 insertions(+), 9 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 2c20927..5965667 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -138,8 +138,7 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S),
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 			   regval);
 	if (ret) {
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -164,8 +163,8 @@ static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S), 0);
+			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
+			   0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
@@ -180,7 +179,7 @@ static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 	int ret;
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(drvdata->variant, LPAIF_I2S_PORT_MI2S),
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
 			LPAIF_I2SCTL_SPKEN_MASK, LPAIF_I2SCTL_SPKEN_ENABLE);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
@@ -201,7 +200,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_I2SCTL_REG(drvdata->variant,
-				LPAIF_I2S_PORT_MI2S),
+						dai->driver->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_ENABLE);
 		if (ret)
@@ -213,7 +212,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_I2SCTL_REG(drvdata->variant,
-				LPAIF_I2S_PORT_MI2S),
+						dai->driver->id),
 				LPAIF_I2SCTL_SPKEN_MASK,
 				LPAIF_I2SCTL_SPKEN_DISABLE);
 		if (ret)
@@ -243,8 +242,7 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai)
 
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant,
-			   LPAIF_I2S_PORT_MI2S), 0);
+			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id), 0);
 	if (ret)
 		dev_err(dai->dev, "%s() error writing to i2sctl reg: %d\n",
 				__func__, ret);
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 4a0e3fb..cc5f3b4 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -43,6 +43,7 @@ enum lpaif_dma_channels {
 };
 
 static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
+	.id	= IPQ806X_LPAIF_I2S_PORT_MI2S,
 	.playback = {
 		.stream_name	= "lpass-cpu-playback",
 		.formats	= SNDRV_PCM_FMTBIT_S16 |
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 04/13] ASoC: qcom: remove hardcoded dma channel
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (2 preceding siblings ...)
  2015-05-16 12:32   ` [PATCH v2 03/13] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-21 20:12     ` Mark Brown
  2015-05-16 12:32   ` [PATCH v2 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
                     ` (10 subsequent siblings)
  14 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch removes hardcoded dma channel value in lpass driver, Now the
dma channel allocation happens in the SOC specific layer. This will
allow different LPASS integrations to use the lpass driver in more
generic way.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-ipq806x.c  | 12 ++++++
 sound/soc/qcom/lpass-platform.c | 93 ++++++++++++++++++++++++++++-------------
 sound/soc/qcom/lpass.h          |  2 +
 3 files changed, 77 insertions(+), 30 deletions(-)

diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index cc5f3b4..2eab828 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -63,6 +63,16 @@ static struct snd_soc_dai_driver ipq806x_lpass_cpu_dai_driver = {
 	.ops    = &asoc_qcom_lpass_cpu_dai_ops,
 };
 
+int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+	return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
+}
+
+int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+	return 0;
+}
+
 struct lpass_variant ipq806x_data = {
 	.i2sctrl_reg_base	= 0x0010,
 	.i2sctrl_reg_stride	= 0x04,
@@ -75,6 +85,8 @@ struct lpass_variant ipq806x_data = {
 	.rdma_channels		= 4,
 	.dai_driver		= &ipq806x_lpass_cpu_dai_driver,
 	.num_dai		= 1,
+	.alloc_dma_channel	= ipq806x_lpass_alloc_dma_channel,
+	.free_dma_channel	= ipq806x_lpass_free_dma_channel,
 };
 
 static const struct of_device_id ipq806x_lpass_cpu_device_id[] = {
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index a38e7ec..fc08891 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -24,6 +24,11 @@
 #include "lpass-lpaif-reg.h"
 #include "lpass.h"
 
+struct lpass_pcm_data {
+	int rdma_ch;
+	int i2s_port;
+};
+
 #define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
 
@@ -78,6 +83,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
@@ -85,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret;
+	int ret, rdma_port = pcm_data->i2s_port;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -95,7 +101,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	regval = LPAIF_RDMACTL_BURSTEN_INCR4 |
-			LPAIF_RDMACTL_AUDINTF_MI2S |
+			LPAIF_RDMACTL_AUDINTF(rdma_port) |
 			LPAIF_RDMACTL_FIFOWM_8;
 
 	switch (bitwidth) {
@@ -151,7 +157,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), regval);
+			LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), regval);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -164,13 +170,14 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 static int lpass_platform_pcmops_hw_free(struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	int ret;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, pcm_data->rdma_ch), 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -182,13 +189,14 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABASE_REG(v, ch),
 			runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabase reg: %d\n",
@@ -197,7 +205,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMABUFF_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMABUFF_REG(v, ch),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmabuff reg: %d\n",
@@ -206,7 +214,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMAPER_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMAPER_REG(v, ch),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmaper reg: %d\n",
@@ -215,7 +223,7 @@ static int lpass_platform_pcmops_prepare(struct snd_pcm_substream *substream)
 	}
 
 	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+			LPAIF_RDMACTL_REG(v, ch),
 			LPAIF_RDMACTL_ENABLE_MASK, LPAIF_RDMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
@@ -230,10 +238,11 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		int cmd)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -242,7 +251,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		/* clear status before enabling interrupts */
 		ret = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ALL(ch));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, ret);
@@ -251,8 +260,8 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ALL(ch),
+				LPAIF_IRQ_ALL(ch));
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 					__func__, ret);
@@ -260,7 +269,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 		}
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, ch),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_ON);
 		if (ret) {
@@ -273,7 +282,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S),
+				LPAIF_RDMACTL_REG(v, ch),
 				LPAIF_RDMACTL_ENABLE_MASK,
 				LPAIF_RDMACTL_ENABLE_OFF);
 		if (ret) {
@@ -284,7 +293,7 @@ static int lpass_platform_pcmops_trigger(struct snd_pcm_substream *substream,
 
 		ret = regmap_update_bits(drvdata->lpaif_map,
 				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S), 0);
+				LPAIF_IRQ_ALL(ch), 0);
 		if (ret) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
 					__func__, ret);
@@ -300,15 +309,15 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_data *drvdata =
 			snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
-	int ret;
+	int ret, ch = pcm_data->rdma_ch;
 
 	ret = regmap_read(drvdata->lpaif_map,
-			 LPAIF_RDMABASE_REG(v, LPAIF_RDMA_CHAN_MI2S),
-			 &base_addr);
+			LPAIF_RDMABASE_REG(v, ch), &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmabase reg: %d\n",
 				__func__, ret);
@@ -316,8 +325,7 @@ static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 	}
 
 	ret = regmap_read(drvdata->lpaif_map,
-			 LPAIF_RDMACURR_REG(v, LPAIF_RDMA_CHAN_MI2S),
-			 &curr_addr);
+			LPAIF_RDMACURR_REG(v, ch), &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error reading from rdmacurr reg: %d\n",
 				__func__, ret);
@@ -355,9 +363,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
+	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
 	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
-	int rv;
+	int rv, chan = pcm_data->rdma_ch;
 
 	rv = regmap_read(drvdata->lpaif_map,
 			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
@@ -366,12 +375,13 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 				__func__, rv);
 		return IRQ_NONE;
 	}
-	interrupts &= LPAIF_IRQ_ALL(LPAIF_RDMA_CHAN_MI2S);
 
-	if (interrupts & LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S)) {
+	interrupts &= LPAIF_IRQ_ALL(chan);
+
+	if (interrupts & LPAIF_IRQ_PER(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_PER(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_PER(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -381,10 +391,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
-	if (interrupts & LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S)) {
+	if (interrupts & LPAIF_IRQ_XRUN(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_XRUN(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_XRUN(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -395,10 +405,10 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
-	if (interrupts & LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S)) {
+	if (interrupts & LPAIF_IRQ_ERR(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
 				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ERR(LPAIF_RDMA_CHAN_MI2S));
+				LPAIF_IRQ_ERR(chan));
 		if (rv) {
 			dev_err(soc_runtime->dev, "%s() error writing to irqclear reg: %d\n",
 					__func__, rv);
@@ -450,10 +460,26 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	struct snd_pcm *pcm = soc_runtime->pcm;
 	struct snd_pcm_substream *substream =
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
+	struct snd_soc_dai *cpu_dai = soc_runtime->cpu_dai;
 	struct lpass_data *drvdata =
 		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
 	int ret;
+	struct lpass_pcm_data *data;
+
+	data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	if (v->alloc_dma_channel)
+		data->rdma_ch = v->alloc_dma_channel(drvdata);
+
+	if (IS_ERR_VALUE(data->rdma_ch))
+		return data->rdma_ch;
+
+	data->i2s_port = cpu_dai->driver->id;
+
+	snd_soc_pcm_set_drvdata(soc_runtime, data);
 
 	soc_runtime->dev->coherent_dma_mask = DMA_BIT_MASK(32);
 	soc_runtime->dev->dma_mask = &soc_runtime->dev->coherent_dma_mask;
@@ -480,7 +506,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 		return ret;
 	}
 	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_RDMACTL_REG(v, LPAIF_RDMA_CHAN_MI2S), 0);
+			LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
@@ -499,6 +525,13 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	struct snd_pcm_substream *substream =
 		pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
+	struct lpass_data *drvdata =
+		snd_soc_platform_get_drvdata(soc_runtime->platform);
+	struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
+	struct lpass_variant *v = drvdata->variant;
+
+	if (v->free_dma_channel)
+		v->free_dma_channel(drvdata, data->rdma_ch);
 
 	lpass_platform_free_buffer(substream, soc_runtime);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index fa00be4..caaf17f 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -63,6 +63,8 @@ struct lpass_variant {
 	/* SOC specific intialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
+	int (*alloc_dma_channel)(struct lpass_data *data);
+	int (*free_dma_channel)(struct lpass_data *data, int ch);
 
 	/* SOC specific dais */
 	struct snd_soc_dai_driver *dai_driver;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 05/13] ASoC: qcom: support bitclk and osrclk per i2s port
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (3 preceding siblings ...)
  2015-05-16 12:32   ` [PATCH v2 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-17 16:14     ` Kenneth Westfield
  2015-05-16 12:32   ` [PATCH v2 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
                     ` (9 subsequent siblings)
  14 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds support to allow bitclk and osrclk per i2s dai port.
on APQ8016 there are 4 i2s ports each one has its own bit clks.

Without this patch its not possible to support multiple i2s ports in the
lpass driver.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 58 ++++++++++++++++++++++++++++++----------------
 sound/soc/qcom/lpass.h     |  5 ++--
 2 files changed, 41 insertions(+), 22 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 5965667..86c9d1a 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,7 +33,7 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_set_rate(drvdata->mi2s_osr_clk, freq);
+	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
 	if (ret)
 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
 				__func__, freq, ret);
@@ -47,18 +47,18 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_prepare_enable(drvdata->mi2s_osr_clk);
+	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
 				__func__, ret);
 		return ret;
 	}
 
-	ret = clk_prepare_enable(drvdata->mi2s_bit_clk);
+	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
 				__func__, ret);
-		clk_disable_unprepare(drvdata->mi2s_osr_clk);
+		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 		return ret;
 	}
 
@@ -70,8 +70,8 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
-	clk_disable_unprepare(drvdata->mi2s_bit_clk);
-	clk_disable_unprepare(drvdata->mi2s_osr_clk);
+	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
+	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -146,7 +146,8 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 		return ret;
 	}
 
-	ret = clk_set_rate(drvdata->mi2s_bit_clk, rate * bitwidth * 2);
+	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
+			   rate * bitwidth * 2);
 	if (ret) {
 		dev_err(dai->dev, "%s() error setting mi2s bitclk to %u: %d\n",
 				__func__, rate * bitwidth * 2, ret);
@@ -354,7 +355,8 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	struct lpass_variant *variant;
 	struct device *dev = &pdev->dev;
 	const struct of_device_id *match;
-	int ret;
+	char clk_name[16];
+	int ret, i, dai_id;
 
 	dsp_of_node = of_parse_phandle(pdev->dev.of_node, "qcom,adsp", 0);
 	if (dsp_of_node) {
@@ -400,18 +402,34 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	if (variant->init)
 		variant->init(pdev);
 
-	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
-	if (IS_ERR(drvdata->mi2s_osr_clk)) {
-		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_osr_clk));
-		return PTR_ERR(drvdata->mi2s_osr_clk);
-	}
-
-	drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");
-	if (IS_ERR(drvdata->mi2s_bit_clk)) {
-		dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk: %ld\n",
-				__func__, PTR_ERR(drvdata->mi2s_bit_clk));
-		return PTR_ERR(drvdata->mi2s_bit_clk);
+	for (i = 0; i < variant->num_dai; i++) {
+		dai_id = variant->dai_driver[i].id;
+		if (variant->num_dai > 1)
+			sprintf(clk_name, "mi2s-osr-clk%d", i);
+		else
+			sprintf(clk_name, "mi2s-osr-clk");
+
+		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
+								clk_name);
+		if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
+			dev_err(&pdev->dev,
+				"%s() error getting mi2s-osr-clk: %ld\n",
+				__func__,
+			return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
+		}
+
+		if (variant->num_dai > 1)
+			sprintf(clk_name, "mi2s-bit-clk%d", i);
+		else
+			sprintf(clk_name, "mi2s-bit-clk");
+
+		drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev, clk_name);
+		if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
+			dev_err(&pdev->dev,
+				"%s() error getting mi2s-bit-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->mi2s_bit_clk[i]));
+			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
+		}
 	}
 
 	drvdata->ahbix_clk = devm_clk_get(&pdev->dev, "ahbix-clk");
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index caaf17f..75e9370 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -22,6 +22,7 @@
 #include <linux/regmap.h>
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
+#define LPASS_MAX_MI2S_PORTS			(8)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -30,10 +31,10 @@ struct lpass_data {
 	struct clk *ahbix_clk;
 
 	/* MI2S system clock */
-	struct clk *mi2s_osr_clk;
+	struct clk *mi2s_osr_clk[LPASS_MAX_MI2S_PORTS];
 
 	/* MI2S bit clock (derived from system clock by a divider */
-	struct clk *mi2s_bit_clk;
+	struct clk *mi2s_bit_clk[LPASS_MAX_MI2S_PORTS];
 
 	/* low-power audio interface (LPAIF) registers */
 	void __iomem *lpaif;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 06/13] ASoC: qcom: make osr clock optional
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (4 preceding siblings ...)
  2015-05-16 12:32   ` [PATCH v2 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-17 16:15     ` Kenneth Westfield
  2015-05-16 12:32   ` [PATCH v2 07/13] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
                     ` (8 subsequent siblings)
  14 siblings, 1 reply; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

Some LPASS integrations like on APQ8016 do not have OSR clk, so making
osr clk optional would allow such integrations to use lpass driver.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-cpu.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 86c9d1a..95369d8 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -33,6 +33,9 @@ static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
+	if (IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+		return 0;
+
 	ret = clk_set_rate(drvdata->mi2s_osr_clk[dai->driver->id], freq);
 	if (ret)
 		dev_err(dai->dev, "%s() error setting mi2s osrclk to %u: %d\n",
@@ -47,18 +50,22 @@ static int lpass_cpu_daiops_startup(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 	int ret;
 
-	ret = clk_prepare_enable(drvdata->mi2s_osr_clk[dai->diver->id]);
-	if (ret) {
-		dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
-				__func__, ret);
-		return ret;
+	if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id])) {
+		ret = clk_prepare_enable(
+				drvdata->mi2s_osr_clk[dai->driver->id]);
+		if (ret) {
+			dev_err(dai->dev, "%s() error in enabling mi2s osr clk: %d\n",
+					__func__, ret);
+			return ret;
+		}
 	}
 
 	ret = clk_prepare_enable(drvdata->mi2s_bit_clk[dai->driver->id]);
 	if (ret) {
 		dev_err(dai->dev, "%s() error in enabling mi2s bit clk: %d\n",
 				__func__, ret);
-		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
+		if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+			clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 		return ret;
 	}
 
@@ -71,7 +78,9 @@ static void lpass_cpu_daiops_shutdown(struct snd_pcm_substream *substream,
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
 
 	clk_disable_unprepare(drvdata->mi2s_bit_clk[dai->driver->id]);
-	clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
+
+	if (!IS_ERR(drvdata->mi2s_osr_clk[dai->driver->id]))
+		clk_disable_unprepare(drvdata->mi2s_osr_clk[dai->driver->id]);
 }
 
 static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
@@ -415,7 +424,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev,
 				"%s() error getting mi2s-osr-clk: %ld\n",
 				__func__,
-			return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
+			PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
 		}
 
 		if (variant->num_dai > 1)
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 07/13] ASoC: qcom: add dma channel control offset to variant data
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (5 preceding siblings ...)
  2015-05-16 12:32   ` [PATCH v2 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
@ 2015-05-16 12:32   ` Srinivas Kandagatla
  2015-05-16 12:33   ` [PATCH v2 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
                     ` (7 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:32 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds ability to pass dma channel control bits start offset, which
differ in differnet qcom SOCs. On apq8016 dma channel control bits start
after an offset of 1.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 2 +-
 sound/soc/qcom/lpass.h          | 5 +++++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index fc08891..8ab0ac1 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -91,7 +91,7 @@ static int lpass_platform_pcmops_hw_params(struct snd_pcm_substream *substream,
 	unsigned int channels = params_channels(params);
 	unsigned int regval;
 	int bitwidth;
-	int ret, rdma_port = pcm_data->i2s_port;
+	int ret, rdma_port = pcm_data->i2s_port + v->rdmactl_audif_start;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 75e9370..023170a 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -61,6 +61,11 @@ struct lpass_variant {
 	u32	rdma_reg_stride;
 	u32	rdma_channels;
 
+	/**
+	 * on SOCs like APQ8016 the channel control bits start
+	 * at different offset to ipq806x
+	 **/
+	u32	rdmactl_audif_start;
 	/* SOC specific intialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (6 preceding siblings ...)
  2015-05-16 12:32   ` [PATCH v2 07/13] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
@ 2015-05-16 12:33   ` Srinivas Kandagatla
  2015-05-16 12:33   ` [PATCH v2 09/13] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
                     ` (6 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:33 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds ablity to lpass driver to handle interrupt per dma
channel. Without this patch its not possible to use multipl ports on the
lpass.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass-platform.c | 94 ++++++++++++++++++++++++++---------------
 sound/soc/qcom/lpass.h          |  4 ++
 2 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 8ab0ac1..79688aa 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -356,27 +356,15 @@ static struct snd_pcm_ops lpass_platform_pcm_ops = {
 	.mmap		= lpass_platform_pcmops_mmap,
 };
 
-static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+static irqreturn_t lpass_dma_interrupt_handler(
+			struct snd_pcm_substream *substream,
+			struct lpass_data *drvdata,
+			int chan, u32 interrupts)
 {
-	struct snd_pcm_substream *substream = data;
 	struct snd_soc_pcm_runtime *soc_runtime = substream->private_data;
-	struct lpass_data *drvdata =
-		snd_soc_platform_get_drvdata(soc_runtime->platform);
 	struct lpass_variant *v = drvdata->variant;
-	struct lpass_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(soc_runtime);
-	unsigned int interrupts;
 	irqreturn_t ret = IRQ_NONE;
-	int rv, chan = pcm_data->rdma_ch;
-
-	rv = regmap_read(drvdata->lpaif_map,
-			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &interrupts);
-	if (rv) {
-		dev_err(soc_runtime->dev, "%s() error reading from irqstat reg: %d\n",
-				__func__, rv);
-		return IRQ_NONE;
-	}
-
-	interrupts &= LPAIF_IRQ_ALL(chan);
+	int rv;
 
 	if (interrupts & LPAIF_IRQ_PER(chan)) {
 		rv = regmap_write(drvdata->lpaif_map,
@@ -422,6 +410,35 @@ static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	return ret;
 }
 
+static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->lpaif_map,
+			LPAIF_IRQSTAT_REG(v, LPAIF_IRQ_PORT_HOST), &irqs);
+	if (rv) {
+		pr_err("%s() error reading from irqstat reg: %d\n",
+				__func__, rv);
+		return IRQ_NONE;
+	}
+
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
+		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
 static int lpass_platform_alloc_buffer(struct snd_pcm_substream *substream,
 		struct snd_soc_pcm_runtime *soc_runtime)
 {
@@ -477,6 +494,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (IS_ERR_VALUE(data->rdma_ch))
 		return data->rdma_ch;
 
+	drvdata->substream[data->rdma_ch] = substream;
 	data->i2s_port = cpu_dai->driver->id;
 
 	snd_soc_pcm_set_drvdata(soc_runtime, data);
@@ -488,29 +506,12 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime)
 	if (ret)
 		return ret;
 
-	ret = devm_request_irq(soc_runtime->dev, drvdata->lpaif_irq,
-			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
-			"lpass-irq-lpaif", substream);
-	if (ret) {
-		dev_err(soc_runtime->dev, "%s() irq request failed: %d\n",
-				__func__, ret);
-		goto err_buf;
-	}
-
-	/* ensure audio hardware is disabled */
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
-	if (ret) {
-		dev_err(soc_runtime->dev, "%s() error writing to irqen reg: %d\n",
-				__func__, ret);
-		return ret;
-	}
 	ret = regmap_write(drvdata->lpaif_map,
 			LPAIF_RDMACTL_REG(v, data->rdma_ch), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev, "%s() error writing to rdmactl reg: %d\n",
 				__func__, ret);
-		return ret;
+		goto err_buf;
 	}
 
 	return 0;
@@ -530,6 +531,8 @@ static void lpass_platform_pcm_free(struct snd_pcm *pcm)
 	struct lpass_pcm_data *data = snd_soc_pcm_get_drvdata(soc_runtime);
 	struct lpass_variant *v = drvdata->variant;
 
+	drvdata->substream[data->rdma_ch] = NULL;
+
 	if (v->free_dma_channel)
 		v->free_dma_channel(drvdata, data->rdma_ch);
 
@@ -545,6 +548,8 @@ static struct snd_soc_platform_driver lpass_platform_driver = {
 int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 {
 	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct lpass_variant *v = drvdata->variant;
+	int ret;
 
 	drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
 	if (drvdata->lpaif_irq < 0) {
@@ -553,6 +558,25 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
+	/* ensure audio hardware is disabled */
+	ret = regmap_write(drvdata->lpaif_map,
+			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() error writing to irqen reg: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
+			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
+			"lpass-irq-lpaif", drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() irq request failed: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+
 	return devm_snd_soc_register_platform(&pdev->dev,
 			&lpass_platform_driver);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 023170a..d572e7b 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -23,6 +23,7 @@
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
 #define LPASS_MAX_MI2S_PORTS			(8)
+#define LPASS_MAX_DMA_CHANNELS			(8)
 
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
@@ -47,6 +48,9 @@ struct lpass_data {
 
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
+
+	/* used it for handling interrupt per dma channel */
+	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 };
 
 /* Vairant data per each SOC */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 09/13] ASoC: qcom: add bit map to track static dma channel allocations
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (7 preceding siblings ...)
  2015-05-16 12:33   ` [PATCH v2 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
@ 2015-05-16 12:33   ` Srinivas Kandagatla
  2015-05-16 12:33   ` [PATCH v2 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
                     ` (5 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:33 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds dma channel bit mask to lpass data to keep track of dma
channel allocations. This flag would be used in apq8016 lpass driver.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/lpass.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index d572e7b..deecae9 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -49,6 +49,9 @@ struct lpass_data {
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
 
+	/* bit map to keep track of static channel allocations */
+	unsigned long rdma_ch_bit_map;
+
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
 };
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 10/13] ASoC: qcom: Add apq8016 lpass driver support
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (8 preceding siblings ...)
  2015-05-16 12:33   ` [PATCH v2 09/13] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
@ 2015-05-16 12:33   ` Srinivas Kandagatla
  2015-05-16 12:33   ` [PATCH v2 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
                     ` (4 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:33 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds apq8016 lpass driver support. APQ8016 has 4 MI2S which
can be routed to one internal codec and 2 external codec interfaces.

Primary, Secondary, Quaternary I2S can do Rx(playback) and Tertiary and
Quaternary can do Tx(capture).

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 include/dt-bindings/sound/apq8016-lpass.h |   9 ++
 sound/soc/qcom/Kconfig                    |   6 +
 sound/soc/qcom/Makefile                   |   2 +
 sound/soc/qcom/lpass-apq8016.c            | 242 ++++++++++++++++++++++++++++++
 sound/soc/qcom/lpass.h                    |   4 +
 5 files changed, 263 insertions(+)
 create mode 100644 include/dt-bindings/sound/apq8016-lpass.h
 create mode 100644 sound/soc/qcom/lpass-apq8016.c

diff --git a/include/dt-bindings/sound/apq8016-lpass.h b/include/dt-bindings/sound/apq8016-lpass.h
new file mode 100644
index 0000000..499076e
--- /dev/null
+++ b/include/dt-bindings/sound/apq8016-lpass.h
@@ -0,0 +1,9 @@
+#ifndef __DT_APQ8016_LPASS_H
+#define __DT_APQ8016_LPASS_H
+
+#define MI2S_PRIMARY	0
+#define MI2S_SECONDARY	1
+#define MI2S_TERTIARY	2
+#define MI2S_QUATERNARY	3
+
+#endif /* __DT_APQ8016_LPASS_H */
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 865205e..9cc5ed7 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -20,6 +20,12 @@ config SND_SOC_LPASS_IPQ806X
 	select SND_SOC_LPASS_CPU
 	select SND_SOC_LPASS_PLATFORM
 
+config SND_SOC_LPASS_APQ8016
+	tristate
+	depends on SND_SOC_QCOM
+	select SND_SOC_LPASS_CPU
+	select SND_SOC_LPASS_PLATFORM
+
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
 	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index f8aab91..ac76308 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -2,10 +2,12 @@
 snd-soc-lpass-cpu-objs := lpass-cpu.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
+snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
+obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 
 # Machine
 snd-soc-storm-objs := storm.o
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
new file mode 100644
index 0000000..367fc46
--- /dev/null
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ *
+ * 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.
+ *
+ * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS
+ *
+ */
+
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+
+#include <dt-bindings/sound/apq8016-lpass.h>
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+
+static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
+	[MI2S_PRIMARY] =  {
+		.id = MI2S_PRIMARY,
+		.name = "Primary MI2S",
+		.playback = {
+			.stream_name	= "Primary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	[MI2S_SECONDARY] =  {
+		.id = MI2S_SECONDARY,
+		.name = "Secondary MI2S",
+		.playback = {
+			.stream_name	= "Secondary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	[MI2S_TERTIARY] =  {
+		.id = MI2S_TERTIARY,
+		.name = "Tertiary MI2S",
+		.capture = {
+			.stream_name	= "Tertiary Capture",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+	[MI2S_QUATERNARY] =  {
+		.id = MI2S_QUATERNARY,
+		.name = "Quatenary MI2S",
+		.playback = {
+			.stream_name	= "Quatenary Playback",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.capture = {
+			.stream_name	= "Quatenary Capture",
+			.formats	= SNDRV_PCM_FMTBIT_S16 |
+						SNDRV_PCM_FMTBIT_S24 |
+						SNDRV_PCM_FMTBIT_S32,
+			.rates		= SNDRV_PCM_RATE_8000 |
+						SNDRV_PCM_RATE_16000 |
+						SNDRV_PCM_RATE_32000 |
+						SNDRV_PCM_RATE_48000 |
+						SNDRV_PCM_RATE_96000,
+			.rate_min	= 8000,
+			.rate_max	= 96000,
+			.channels_min	= 1,
+			.channels_max	= 8,
+		},
+		.probe	= &asoc_qcom_lpass_cpu_dai_probe,
+		.ops    = &asoc_qcom_lpass_cpu_dai_ops,
+	},
+};
+
+static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata)
+{
+	struct lpass_variant *v = drvdata->variant;
+	int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map,
+					v->rdma_channels);
+
+	if (chan >= v->rdma_channels)
+		return -EBUSY;
+
+	set_bit(chan, &drvdata->rdma_ch_bit_map);
+
+	return chan;
+}
+
+static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+{
+	clear_bit(chan, &drvdata->rdma_ch_bit_map);
+
+	return 0;
+}
+
+static int apq8016_lpass_init(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk");
+	if (IS_ERR(drvdata->pcnoc_mport_clk)) {
+		dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->pcnoc_mport_clk));
+		return PTR_ERR(drvdata->pcnoc_mport_clk);
+	}
+
+	ret = clk_prepare_enable(drvdata->pcnoc_mport_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() Error enabling pcnoc-mport-clk: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk");
+	if (IS_ERR(drvdata->pcnoc_sway_clk)) {
+		dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n",
+				__func__, PTR_ERR(drvdata->pcnoc_sway_clk));
+		return PTR_ERR(drvdata->pcnoc_sway_clk);
+	}
+
+	ret = clk_prepare_enable(drvdata->pcnoc_sway_clk);
+	if (ret) {
+		dev_err(&pdev->dev, "%s() Error enabling pcnoc_sway_clk: %d\n",
+				__func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int apq8016_lpass_exit(struct platform_device *pdev)
+{
+	struct lpass_data *drvdata = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(drvdata->pcnoc_mport_clk);
+	clk_disable_unprepare(drvdata->pcnoc_sway_clk);
+
+	return 0;
+}
+
+
+struct lpass_variant apq8016_data = {
+	.i2sctrl_reg_base	= 0x1000,
+	.i2sctrl_reg_stride	= 0x1000,
+	.i2s_ports		= 4,
+	.irq_reg_base		= 0x6000,
+	.irq_reg_stride		= 0x1000,
+	.irq_ports		= 3,
+	.rdma_reg_base		= 0x8400,
+	.rdma_reg_stride	= 0x1000,
+	.rdma_channels		= 2,
+	.rdmactl_audif_start	= 1,
+	.dai_driver		= apq8016_lpass_cpu_dai_driver,
+	.num_dai		= ARRAY_SIZE(apq8016_lpass_cpu_dai_driver),
+	.init			= apq8016_lpass_init,
+	.exit			= apq8016_lpass_exit,
+	.alloc_dma_channel	= apq8016_lpass_alloc_dma_channel,
+	.free_dma_channel	= apq8016_lpass_free_dma_channel,
+};
+
+static const struct of_device_id apq8016_lpass_cpu_device_id[] = {
+	{ .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data },
+	{}
+};
+MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id);
+
+static struct platform_driver apq8016_lpass_cpu_platform_driver = {
+	.driver	= {
+		.name		= "apq8016-lpass-cpu",
+		.of_match_table	= of_match_ptr(apq8016_lpass_cpu_device_id),
+	},
+	.probe	= asoc_qcom_lpass_cpu_platform_probe,
+	.remove	= asoc_qcom_lpass_cpu_platform_remove,
+};
+module_platform_driver(apq8016_lpass_cpu_platform_driver);
+
+MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver");
+MODULE_LICENSE("GPL v2");
+
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index deecae9..d6e86c1 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -54,6 +54,10 @@ struct lpass_data {
 
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
+
+	/* 8016 specific */
+	struct clk *pcnoc_mport_clk;
+	struct clk *pcnoc_sway_clk;
 };
 
 /* Vairant data per each SOC */
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 11/13] ASoC: qcom: add apq8016 sound card support
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (9 preceding siblings ...)
  2015-05-16 12:33   ` [PATCH v2 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
@ 2015-05-16 12:33   ` Srinivas Kandagatla
  2015-05-16 12:33   ` [PATCH v2 12/13] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
                     ` (3 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:33 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds apq8016 machine driver support. This patch was tested on
two apq8016-sbc and msm8916-mtp board for both hdmi and analog audio
features.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 sound/soc/qcom/Kconfig       |   9 ++
 sound/soc/qcom/Makefile      |   2 +
 sound/soc/qcom/apq8016_sbc.c | 215 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 226 insertions(+)
 create mode 100644 sound/soc/qcom/apq8016_sbc.c

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 9cc5ed7..03b5e92 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -34,3 +34,12 @@ config SND_SOC_STORM
 	help
           Say Y or M if you want add support for SoC audio on the
           Qualcomm Technologies IPQ806X-based Storm board.
+
+config SND_SOC_APQ8016_SBC
+	tristate "SoC Audio support for APQ8016 SBC platforms"
+	depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST
+	select SND_SOC_LPASS_APQ8016
+	help
+          Support for Qualcomm Technologies LPASS audio block in
+          APQ8016 SOC-based systems.
+          Say Y if you want to use audio devices on MI2S
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index ac76308..79e5c50 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -11,5 +11,7 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
 
 # Machine
 snd-soc-storm-objs := storm.o
+snd-soc-apq8016-sbc-objs := apq8016_sbc.o
 
 obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o
+obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
new file mode 100644
index 0000000..8958633
--- /dev/null
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (c) 2015 The Linux Foundation. All rights reserved.
+ *
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <dt-bindings/sound/apq8016-lpass.h>
+
+struct apq8016_sbc_data {
+	void __iomem *mic_iomux;
+	void __iomem *spkr_iomux;
+	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
+};
+
+#define MIC_CTRL_QUA_WS_SLAVE_SEL_10	BIT(17)
+#define MIC_CTRL_TLMM_SCLK_EN		BIT(1)
+#define	SPKR_CTL_PRI_WS_SLAVE_SEL_11	(BIT(17) | BIT(16))
+
+static int apq8016_sbc_startup(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_card *card = rtd->card;
+	struct apq8016_sbc_data *pdata = snd_soc_card_get_drvdata(card);
+
+	if (cpu_dai->id == MI2S_QUATERNARY) {
+		/* Configure the Quat MI2S to TLMM */
+		writel(readl(pdata->mic_iomux) |
+			MIC_CTRL_QUA_WS_SLAVE_SEL_10 |
+			MIC_CTRL_TLMM_SCLK_EN,
+			pdata->mic_iomux);
+
+		return 0;
+	} else if (cpu_dai->id == MI2S_PRIMARY) {
+		writel(readl(pdata->spkr_iomux) |
+			SPKR_CTL_PRI_WS_SLAVE_SEL_11,
+			pdata->spkr_iomux);
+
+		return 0;
+	}
+
+	dev_err(card->dev, "unsupported cpu dai configuration\n");
+
+	return -EINVAL;
+}
+
+static struct snd_soc_ops apq8016_sbc_soc_ops = {
+	.startup	= apq8016_sbc_startup,
+};
+
+static struct apq8016_sbc_data *apq8016_sbc_parse_of(struct snd_soc_card *card)
+{
+	int num_links;
+	struct device *dev = card->dev;
+	struct snd_soc_dai_link *dai_link;
+	struct device_node *np, *codec, *cpu, *node  = dev->of_node;
+	struct apq8016_sbc_data *data;
+	char *name;
+	int ret;
+
+	/* Populate links */
+	num_links = of_get_child_count(node);
+
+	/* Allocate the private data and the DAI link array */
+	data = devm_kzalloc(dev, sizeof(*data) + sizeof(*dai_link) * num_links,
+			    GFP_KERNEL);
+	if (!data)
+		return ERR_PTR(-ENOMEM);
+
+	card->dai_link	= &data->dai_link[0];
+	card->num_links	= num_links;
+
+	dai_link = data->dai_link;
+
+	for_each_child_of_node(node, np) {
+		cpu = of_get_child_by_name(np, "cpu");
+		codec = of_get_child_by_name(np, "codec");
+
+		if (!cpu || !codec) {
+			dev_err(dev, "Can't find cpu/codec DT node\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		dai_link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
+		if (!dai_link->cpu_of_node) {
+			dev_err(card->dev, "error getting cpu phandle\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		dai_link->codec_of_node = of_parse_phandle(codec,
+							   "sound-dai",
+							   0);
+		if (!dai_link->codec_of_node) {
+			dev_err(card->dev, "error getting codec phandle\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		ret = snd_soc_of_get_dai_name(cpu, &dai_link->cpu_dai_name);
+		if (ret) {
+			dev_err(card->dev, "error getting cpu dai name\n");
+			return ERR_PTR(ret);
+		}
+
+		ret = snd_soc_of_get_dai_name(codec, &dai_link->codec_dai_name);
+		if (ret) {
+			dev_err(card->dev, "error getting codec dai name\n");
+			return ERR_PTR(ret);
+		}
+
+		dai_link->platform_of_node = dai_link->cpu_of_node;
+		/* For now we only support playback */
+		dai_link->playback_only = true;
+
+		if (of_property_read_bool(np, "external"))
+			name = "HDMI";
+
+		else
+			name = "Headset";
+
+		dai_link->ops = &apq8016_sbc_soc_ops;
+		dai_link->name = dai_link->stream_name = name;
+
+		dai_link++;
+	}
+
+	return data;
+}
+
+static int apq8016_sbc_platform_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct snd_soc_card *card;
+	struct apq8016_sbc_data *data;
+	struct resource *res;
+	int ret;
+
+	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+	if (!card)
+		return -ENOMEM;
+
+	card->dev = dev;
+	data = apq8016_sbc_parse_of(card);
+	if (IS_ERR(data)) {
+		dev_err(&pdev->dev, "Error resolving dai links: %ld\n",
+			PTR_ERR(data));
+		return PTR_ERR(data);
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mic-iomux");
+	data->mic_iomux = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->mic_iomux))
+		return PTR_ERR(data->mic_iomux);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "spkr-iomux");
+	data->spkr_iomux = devm_ioremap_resource(dev, res);
+	if (IS_ERR(data->spkr_iomux))
+		return PTR_ERR(data->spkr_iomux);
+
+	platform_set_drvdata(pdev, data);
+	snd_soc_card_set_drvdata(card, data);
+
+	ret = snd_soc_of_parse_card_name(card, "qcom,model");
+	if (ret) {
+		dev_err(&pdev->dev, "Error parsing card name: %d\n", ret);
+		return ret;
+	}
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret == -EPROBE_DEFER) {
+		card->dev = NULL;
+		return ret;
+	} else if (ret) {
+		dev_err(&pdev->dev, "Error registering soundcard: %d\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct of_device_id apq8016_sbc_device_id[]  = {
+	{ .compatible = "qcom,apq8016-sbc-sndcard" },
+	{},
+};
+MODULE_DEVICE_TABLE(of, apq8016_sbc_device_id);
+
+static struct platform_driver apq8016_sbc_platform_driver = {
+	.driver = {
+		.name = "qcom-apq8016-sbc",
+		.of_match_table = of_match_ptr(apq8016_sbc_device_id),
+	},
+	.probe = apq8016_sbc_platform_probe,
+};
+module_platform_driver(apq8016_sbc_platform_driver);
+
+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org");
+MODULE_DESCRIPTION("APQ8016 ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 12/13] ASoC: qcom: Document apq8016 bindings.
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (10 preceding siblings ...)
  2015-05-16 12:33   ` [PATCH v2 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
@ 2015-05-16 12:33   ` Srinivas Kandagatla
  2015-05-16 12:33   ` [PATCH v2 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings Srinivas Kandagatla
                     ` (2 subsequent siblings)
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:33 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch updates lpass bindings with apq8016 specific bindings.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
index e00732d..21c6483 100644
--- a/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
+++ b/Documentation/devicetree/bindings/sound/qcom,lpass-cpu.txt
@@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
 
 Required properties:
 
-- compatible		: "qcom,lpass-cpu"
+- compatible		: "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
 - clocks		: Must contain an entry for each entry in clock-names.
 - clock-names		: A list which must include the following entries:
 				* "ahbix-clk"
 				* "mi2s-osr-clk"
 				* "mi2s-bit-clk"
+			: required clocks for "qcom,lpass-cpu-apq8016"
+				* "ahbix-clk"
+				* "mi2s-bit-clk0"
+				* "mi2s-bit-clk1"
+				* "mi2s-bit-clk2"
+				* "mi2s-bit-clk3"
+				* "pcnoc-mport-clk"
+				* "pcnoc-sway-clk"
+
 - interrupts		: Must contain an entry for each entry in
 			  interrupt-names.
 - interrupt-names	: A list which must include the following entries:
@@ -22,6 +31,8 @@ Required properties:
 - reg-names		: A list which must include the following entries:
 				* "lpass-lpaif"
 
+
+
 Optional properties:
 
 - qcom,adsp		: Phandle for the audio DSP node
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* [PATCH v2 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (11 preceding siblings ...)
  2015-05-16 12:33   ` [PATCH v2 12/13] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
@ 2015-05-16 12:33   ` Srinivas Kandagatla
  2015-05-17 16:15   ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
  2015-05-21 17:05   ` Mark Brown
  14 siblings, 0 replies; 88+ messages in thread
From: Srinivas Kandagatla @ 2015-05-16 12:33 UTC (permalink / raw)
  To: Patrick Lai, Mark Brown
  Cc: Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm, Srinivas Kandagatla

This patch adds bindings for apq8016 sbc machine driver.
On APQ8016 4 MI2S can be configured to different sinks like internal
codec/external codec, this connection is controlled via 2 iomux
registers.

Tested-by: Kenneth Westfield <kwestfie@codeaurora.org>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
---
 .../devicetree/bindings/sound/qcom,apq8016-sbc.txt | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt

diff --git a/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
new file mode 100644
index 0000000..01d62be
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
@@ -0,0 +1,61 @@
+* Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver
+
+Required properties:
+
+- compatible		: "qcom,apq8016-sbc-sndcard"
+
+- pinctrl-N		: One property must exist for each entry in
+			  pinctrl-names.  See ../pinctrl/pinctrl-bindings.txt
+			  for details of the property values.
+- pinctrl-names		: Must contain a "default" entry.
+- reg			: Must contain an address for each entry in reg-names.
+- reg-names		: A list which must include the following entries:
+				* "mic-iomux"
+				* "spkr-iomux"
+- qcom,model		: Name of the sound card.
+
+Dai-link subnode properties and subnodes:
+
+Required dai-link subnodes:
+
+- cpu					: CPU   sub-node
+- codec					: CODEC sub-node
+
+Required CPU/CODEC subnodes properties:
+
+-sound-dai		: phandle and port of CPU/CODEC
+-capture-dai		: phandle and port of CPU/CODEC
+
+Optional CPU/CODEC subnodes properties:
+- external	: flag to indicate if the I2S is connected to external codec
+Example:
+
+sound: sound {
+	compatible = "qcom,apq8016-sbc-sndcard";
+	reg = <0x07702000 0x4>, <0x07702004 0x4>;
+	reg-names = "mic-iomux", "spkr-iomux";
+	qcom,model = "DB410c";
+
+	/* I2S - Internal codec */
+	internal-dai-link@0 {
+		cpu { /* PRIMARY */
+			sound-dai = <&lpass MI2S_PRIMARY>;
+		};
+		codec {
+			sound-dai = <&wcd_codec 0>;
+		};
+	};
+
+	/* External Primary or External Secondary -ADV7533 HDMI */
+	external-dai-link@0 {
+		external;
+		cpu { /* QUAT */
+			sound-dai = <&lpass MI2S_QUATERNARY>;
+		};
+		codec {
+			sound-dai = <&adv_bridge 0>;
+		};
+	};
+};
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 05/13] ASoC: qcom: support bitclk and osrclk per i2s port
  2015-05-16 12:32   ` [PATCH v2 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
@ 2015-05-17 16:14     ` Kenneth Westfield
  0 siblings, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-17 16:14 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Sat, May 16, 2015 at 05:32:42AM -0700, Srinivas Kandagatla wrote:
> This patch adds support to allow bitclk and osrclk per i2s dai port.
> on APQ8016 there are 4 i2s ports each one has its own bit clks.
> 
> Without this patch its not possible to support multiple i2s ports in the
> lpass driver.

> @@ -400,18 +402,34 @@ int asoc_qcom_lpass_cpu_platform_probe(struct
> platform_device *pdev)
>  	if (variant->init)
>  		variant->init(pdev);
>  
> -	drvdata->mi2s_osr_clk = devm_clk_get(&pdev->dev, "mi2s-osr-clk");
> -	if (IS_ERR(drvdata->mi2s_osr_clk)) {
> -		dev_err(&pdev->dev, "%s() error getting mi2s-osr-clk:
> %ld\n",
> -				__func__, PTR_ERR(drvdata->mi2s_osr_clk));
> -		return PTR_ERR(drvdata->mi2s_osr_clk);
> -	}
> -
> -	drvdata->mi2s_bit_clk = devm_clk_get(&pdev->dev, "mi2s-bit-clk");
> -	if (IS_ERR(drvdata->mi2s_bit_clk)) {
> -		dev_err(&pdev->dev, "%s() error getting mi2s-bit-clk:
> %ld\n",
> -				__func__, PTR_ERR(drvdata->mi2s_bit_clk));
> -		return PTR_ERR(drvdata->mi2s_bit_clk);
> +	for (i = 0; i < variant->num_dai; i++) {
> +		dai_id = variant->dai_driver[i].id;
> +		if (variant->num_dai > 1)
> +			sprintf(clk_name, "mi2s-osr-clk%d", i);
> +		else
> +			sprintf(clk_name, "mi2s-osr-clk");
> +
> +		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(&pdev->dev,
> +								clk_name);
> +		if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
> +			dev_err(&pdev->dev,
> +				"%s() error getting mi2s-osr-clk: %ld\n",
> +				__func__,
> +			return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));

Should the previous two lines be:

+                             __func__, PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
+                     return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]);

as you remove the return in patch 6?

> +		}
> +
> +		if (variant->num_dai > 1)
> +			sprintf(clk_name, "mi2s-bit-clk%d", i);
> +		else
> +			sprintf(clk_name, "mi2s-bit-clk");
> +
> +		drvdata->mi2s_bit_clk[dai_id] = devm_clk_get(&pdev->dev,
> clk_name);
> +		if (IS_ERR(drvdata->mi2s_bit_clk[dai_id])) {
> +			dev_err(&pdev->dev,
> +				"%s() error getting mi2s-bit-clk: %ld\n",
> +				__func__,
> PTR_ERR(drvdata->mi2s_bit_clk[i]));
> +			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
> +		}
>  	}

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 06/13] ASoC: qcom: make osr clock optional
  2015-05-16 12:32   ` [PATCH v2 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
@ 2015-05-17 16:15     ` Kenneth Westfield
  0 siblings, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-17 16:15 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Sat, May 16, 2015 at 05:32:49AM -0700, Srinivas Kandagatla wrote:
> Some LPASS integrations like on APQ8016 do not have OSR clk, so making
> osr clk optional would allow such integrations to use lpass driver.

> @@ -415,7 +424,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct
> platform_device *pdev)
>  			dev_err(&pdev->dev,
>  				"%s() error getting mi2s-osr-clk: %ld\n",
>  				__func__,
> -			return PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
> +			PTR_ERR(drvdata->mi2s_osr_clk[dai_id]));
>  		}

NIT:
Perhaps make this a dev_warn or dev_notice log message, as it's no longer
really an error.

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (12 preceding siblings ...)
  2015-05-16 12:33   ` [PATCH v2 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings Srinivas Kandagatla
@ 2015-05-17 16:15   ` Kenneth Westfield
  2015-05-21 17:05   ` Mark Brown
  14 siblings, 0 replies; 88+ messages in thread
From: Kenneth Westfield @ 2015-05-17 16:15 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Mark Brown, Rob Herring, Pawel Moll, Ian Campbell,
	Kumar Gala, Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

On Sat, May 16, 2015 at 05:31:02AM -0700, Srinivas Kandagatla wrote:
> Thankyou for reviewing the v1 patches, here is the v2 patchset after
> incorporating review comments and testing on Storm Board.
> This patchset adds apq8016 audio support into lpass driver. Existing
> Lpass driver can not be used as-it-is for apq8016 as it contains code
> specific to ipq806x. Also the driver only supports single i2s port,
> single dma channel and single bitclk control.
> 
> APQ8016 has 4 MI2S( Primary, Secondary, Tertiary, Quaternary) which can be
> routed
> to internal wcd codec or external codecs. This routing is controlled by 2
> mux
> registers.
> 
> This patch series firstly re-organizes the lpass driver such that the SOC
> specific bits are moved away from the driver. And secondly the SOC
> specifics
> are now passed as lpass variant data which would include various register
> offsets, dma channel allocations and SOC specific clock handling.
> 
> Finally the last few patchs add apq8016 lpass and machine driver.
> 
> All these patches are tested for HDMI audio via adv7533 bridge and Analog
> audio
> on APQ8016-SBC, msm8916-mtp boards and Kenneth tested this patchset on
> ipq806x Storm board too.

Other than the two comments on patches 5 and 6, everything else looks
fine to me.

Acked-by: Kenneth Westfield <kwestfie@codeaurora.org>

-- 
Kenneth Westfield
Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, 
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio
  2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
                     ` (13 preceding siblings ...)
  2015-05-17 16:15   ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
@ 2015-05-21 17:05   ` Mark Brown
  14 siblings, 0 replies; 88+ messages in thread
From: Mark Brown @ 2015-05-21 17:05 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 286 bytes --]

On Sat, May 16, 2015 at 01:31:02PM +0100, Srinivas Kandagatla wrote:
> Thankyou for reviewing the v1 patches, here is the v2 patchset after
> incorporating review comments and testing on Storm Board.

Please don't send new serieses in reply to old ones, it makes them
harder to notice.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF
  2015-05-16 12:32   ` [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
@ 2015-05-21 20:10     ` Mark Brown
  0 siblings, 0 replies; 88+ messages in thread
From: Mark Brown @ 2015-05-21 20:10 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 205 bytes --]

On Sat, May 16, 2015 at 01:32:09PM +0100, Srinivas Kandagatla wrote:
> lpass driver only support DT so make this explicit in the kconfig.

This doesn't apply against current code, please check and resend.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver.
  2015-05-16 12:32   ` [PATCH v2 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
@ 2015-05-21 20:11     ` Mark Brown
  0 siblings, 0 replies; 88+ messages in thread
From: Mark Brown @ 2015-05-21 20:11 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 294 bytes --]

On Sat, May 16, 2015 at 01:32:17PM +0100, Srinivas Kandagatla wrote:
> This patch tries to make the lpass driver more generic by moving the
> ipq806x specific bits out of the cpu and platform driver, also allows the
> SOC specific drivers to add the correct register offsets.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

* Re: [PATCH v2 04/13] ASoC: qcom: remove hardcoded dma channel
  2015-05-16 12:32   ` [PATCH v2 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
@ 2015-05-21 20:12     ` Mark Brown
  0 siblings, 0 replies; 88+ messages in thread
From: Mark Brown @ 2015-05-21 20:12 UTC (permalink / raw)
  To: Srinivas Kandagatla
  Cc: Patrick Lai, Rob Herring, Pawel Moll, Ian Campbell, Kumar Gala,
	Banajit Goswami, Kenneth Westfield, Liam Girdwood,
	Jaroslav Kysela, Takashi Iwai, devicetree, linux-kernel,
	alsa-devel, linux-arm-msm

[-- Attachment #1: Type: text/plain, Size: 315 bytes --]

On Sat, May 16, 2015 at 01:32:34PM +0100, Srinivas Kandagatla wrote:
> This patch removes hardcoded dma channel value in lpass driver, Now the
> dma channel allocation happens in the SOC specific layer. This will
> allow different LPASS integrations to use the lpass driver in more
> generic way.

Applied, thanks.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]

^ permalink raw reply	[flat|nested] 88+ messages in thread

end of thread, other threads:[~2015-05-21 20:12 UTC | newest]

Thread overview: 88+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-30 17:15 [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
2015-04-30 17:16 ` [RFC PATCH 01/14] ASoC: qcom: Remove redundant error check Srinivas Kandagatla
2015-05-04 12:24   ` Mark Brown
2015-04-30 17:16 ` [RFC PATCH 02/14] ASoC: qcom: remove unnecessary header files Srinivas Kandagatla
2015-05-04 12:24   ` Mark Brown
2015-04-30 17:16 ` [RFC PATCH 03/14] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
2015-05-02 23:57   ` Kenneth Westfield
2015-05-05  5:19     ` Kenneth Westfield
2015-05-05  7:17       ` Srinivas Kandagatla
2015-05-06  5:43         ` [alsa-devel] " Kenneth Westfield
2015-05-05  7:16     ` Srinivas Kandagatla
2015-05-06  5:35       ` [alsa-devel] " Kenneth Westfield
2015-04-30 17:17 ` [RFC PATCH 04/14] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 05/14] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 06/14] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 07/14] ASoC: qcom: add no osr clk flag to lpass variant Srinivas Kandagatla
2015-05-02 23:58   ` Kenneth Westfield
2015-05-05  7:17     ` Srinivas Kandagatla
2015-05-04 12:26   ` Mark Brown
2015-05-05  7:16     ` Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 08/14] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
2015-05-02 23:59   ` Kenneth Westfield
2015-05-05  7:16     ` Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 09/14] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
2015-05-03  0:00   ` Kenneth Westfield
2015-05-05  7:17     ` Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 10/14] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
2015-04-30 17:17 ` [RFC PATCH 11/14] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
2015-04-30 17:18 ` [RFC PATCH 12/14] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
2015-05-03  0:01   ` Kenneth Westfield
2015-05-05  7:17     ` Srinivas Kandagatla
2015-04-30 17:18 ` [RFC PATCH 13/14] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
2015-04-30 17:18 ` [RFC PATCH 14/14] ASoC: qcom: document apq8016 machine driver bindings Srinivas Kandagatla
2015-05-03  0:03   ` Kenneth Westfield
2015-05-03  3:59     ` Kenneth Westfield
2015-05-05  7:17     ` Srinivas Kandagatla
2015-05-06  5:41       ` [alsa-devel] " Kenneth Westfield
2015-05-02 23:57 ` [RFC PATCH 00/14] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
2015-05-06  5:47   ` Kenneth Westfield
2015-05-06  6:54     ` Srinivas Kandagatla
2015-05-12  4:06       ` [alsa-devel] " Kenneth Westfield
2015-05-12 10:21         ` Srinivas Kandagatla
2015-05-12 17:04           ` Lars-Peter Clausen
2015-05-14  7:55             ` Srinivas Kandagatla
2015-05-12 13:11         ` Srinivas Kandagatla
2015-05-13 11:58 ` [PATCH v1 00/13] " Srinivas Kandagatla
2015-05-13 12:00   ` [PATCH v1 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
2015-05-13 12:00   ` [PATCH v1 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
2015-05-15  5:23     ` Kenneth Westfield
2015-05-15  8:48       ` Srinivas Kandagatla
2015-05-13 12:00   ` [PATCH v1 03/13] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
2015-05-13 12:00   ` [PATCH v1 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
2015-05-13 12:00   ` [PATCH v1 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
2015-05-15  5:23     ` Kenneth Westfield
2015-05-15  8:44       ` Srinivas Kandagatla
2015-05-13 12:02   ` [PATCH v1 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
2015-05-13 12:02   ` [PATCH v1 07/13] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
2015-05-13 12:02   ` [PATCH v1 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
2015-05-13 12:02   ` [PATCH v1 09/13] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
2015-05-13 12:03   ` [PATCH v1 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
2015-05-15  5:23     ` Kenneth Westfield
2015-05-15  8:46       ` Srinivas Kandagatla
2015-05-13 12:03   ` [PATCH v1 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
2015-05-15  5:23     ` Kenneth Westfield
2015-05-15  8:47       ` Srinivas Kandagatla
2015-05-13 12:03   ` [PATCH v1 12/13] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
2015-05-13 12:03   ` [PATCH v1 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings Srinivas Kandagatla
2015-05-16 12:31 ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Srinivas Kandagatla
2015-05-16 12:32   ` [PATCH v2 01/13] ASoC: qcom: make lpass driver depend on OF Srinivas Kandagatla
2015-05-21 20:10     ` Mark Brown
2015-05-16 12:32   ` [PATCH v2 02/13] ASoC: qcom: move ipq806x specific bits out of lpass driver Srinivas Kandagatla
2015-05-21 20:11     ` Mark Brown
2015-05-16 12:32   ` [PATCH v2 03/13] ASoC: qcom: remove hardcoded i2s port number Srinivas Kandagatla
2015-05-16 12:32   ` [PATCH v2 04/13] ASoC: qcom: remove hardcoded dma channel Srinivas Kandagatla
2015-05-21 20:12     ` Mark Brown
2015-05-16 12:32   ` [PATCH v2 05/13] ASoC: qcom: support bitclk and osrclk per i2s port Srinivas Kandagatla
2015-05-17 16:14     ` Kenneth Westfield
2015-05-16 12:32   ` [PATCH v2 06/13] ASoC: qcom: make osr clock optional Srinivas Kandagatla
2015-05-17 16:15     ` Kenneth Westfield
2015-05-16 12:32   ` [PATCH v2 07/13] ASoC: qcom: add dma channel control offset to variant data Srinivas Kandagatla
2015-05-16 12:33   ` [PATCH v2 08/13] ASoC: qcom: Add ability to handle interrupts per dma channel Srinivas Kandagatla
2015-05-16 12:33   ` [PATCH v2 09/13] ASoC: qcom: add bit map to track static dma channel allocations Srinivas Kandagatla
2015-05-16 12:33   ` [PATCH v2 10/13] ASoC: qcom: Add apq8016 lpass driver support Srinivas Kandagatla
2015-05-16 12:33   ` [PATCH v2 11/13] ASoC: qcom: add apq8016 sound card support Srinivas Kandagatla
2015-05-16 12:33   ` [PATCH v2 12/13] ASoC: qcom: Document apq8016 bindings Srinivas Kandagatla
2015-05-16 12:33   ` [PATCH v2 13/13] ASoC: qcom: document apq8016 sbc machine driver bindings Srinivas Kandagatla
2015-05-17 16:15   ` [PATCH v2 00/13] ASoC: qcom: add support to apq8016 audio Kenneth Westfield
2015-05-21 17:05   ` Mark Brown

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).