Update Linux to v5.4.2
Change-Id: Idf6911045d9d382da2cfe01b1edff026404ac8fd
diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index 2a4c912..6008685 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
config SND_SOC_QCOM
tristate "ASoC support for QCOM platforms"
depends on ARCH_QCOM || COMPILE_TEST
@@ -66,6 +67,7 @@
tristate
config SND_SOC_QDSP6_ASM_DAI
+ select SND_SOC_COMPRESS
tristate
config SND_SOC_QDSP6
@@ -97,9 +99,12 @@
config SND_SOC_SDM845
tristate "SoC Machine driver for SDM845 boards"
- depends on QCOM_APR
+ depends on QCOM_APR && CROS_EC && I2C
select SND_SOC_QDSP6
select SND_SOC_QCOM_COMMON
+ select SND_SOC_RT5663
+ select SND_SOC_MAX98927
+ select SND_SOC_CROS_EC_CODEC
help
To add support for audio on Qualcomm Technologies Inc.
SDM845 SoC-based systems.
diff --git a/sound/soc/qcom/apq8016_sbc.c b/sound/soc/qcom/apq8016_sbc.c
index 1dd23bb..ac75838 100644
--- a/sound/soc/qcom/apq8016_sbc.c
+++ b/sound/soc/qcom/apq8016_sbc.c
@@ -1,15 +1,6 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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>
@@ -126,6 +117,7 @@
struct snd_soc_dai_link *link;
struct device_node *np, *codec, *cpu, *node = dev->of_node;
struct apq8016_sbc_data *data;
+ struct snd_soc_dai_link_component *dlc;
int ret, num_links;
ret = snd_soc_of_parse_card_name(card, "qcom,model");
@@ -159,46 +151,67 @@
link = data->dai_link;
for_each_child_of_node(node, np) {
+ dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
+ if (!dlc)
+ return ERR_PTR(-ENOMEM);
+
+ link->cpus = &dlc[0];
+ link->platforms = &dlc[1];
+
+ link->num_cpus = 1;
+ link->num_platforms = 1;
+
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);
+ ret = -EINVAL;
+ goto error;
}
- link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0);
- if (!link->cpu_of_node) {
+ link->cpus->of_node = of_parse_phandle(cpu, "sound-dai", 0);
+ if (!link->cpus->of_node) {
dev_err(card->dev, "error getting cpu phandle\n");
- return ERR_PTR(-EINVAL);
+ ret = -EINVAL;
+ goto error;
}
- ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
+ ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name);
if (ret) {
dev_err(card->dev, "error getting cpu dai name\n");
- return ERR_PTR(ret);
+ goto error;
}
ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
if (ret < 0) {
dev_err(card->dev, "error getting codec dai name\n");
- return ERR_PTR(ret);
+ goto error;
}
- link->platform_of_node = link->cpu_of_node;
+ link->platforms->of_node = link->cpus->of_node;
ret = of_property_read_string(np, "link-name", &link->name);
if (ret) {
dev_err(card->dev, "error getting codec dai_link name\n");
- return ERR_PTR(ret);
+ goto error;
}
link->stream_name = link->name;
link->init = apq8016_sbc_dai_init;
link++;
+
+ of_node_put(cpu);
+ of_node_put(codec);
}
return data;
+
+ error:
+ of_node_put(np);
+ of_node_put(cpu);
+ of_node_put(codec);
+ return ERR_PTR(ret);
}
static const struct snd_soc_dapm_widget apq8016_sbc_dapm_widgets[] = {
diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c
index 1543e85..94363fd 100644
--- a/sound/soc/qcom/apq8096.c
+++ b/sound/soc/qcom/apq8096.c
@@ -9,6 +9,10 @@
#include <sound/pcm.h>
#include "common.h"
+#define SLIM_MAX_TX_PORTS 16
+#define SLIM_MAX_RX_PORTS 16
+#define WCD9335_DEFAULT_MCLK_RATE 9600000
+
static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -23,15 +27,79 @@
return 0;
}
+static int msm_snd_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ u32 rx_ch_cnt = 0, tx_ch_cnt = 0;
+ int ret = 0;
+
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch);
+ if (ret != 0 && ret != -ENOTSUPP) {
+ pr_err("failed to get codec chan map, err:%d\n", ret);
+ goto end;
+ } else if (ret == -ENOTSUPP) {
+ return 0;
+ }
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, NULL,
+ rx_ch_cnt, rx_ch);
+ else
+ ret = snd_soc_dai_set_channel_map(cpu_dai, tx_ch_cnt, tx_ch,
+ 0, NULL);
+ if (ret != 0 && ret != -ENOTSUPP)
+ pr_err("Failed to set cpu chan map, err:%d\n", ret);
+ else if (ret == -ENOTSUPP)
+ ret = 0;
+end:
+ return ret;
+}
+
+static struct snd_soc_ops apq8096_ops = {
+ .hw_params = msm_snd_hw_params,
+};
+
+static int apq8096_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+
+ /*
+ * Codec SLIMBUS configuration
+ * RX1, RX2, RX3, RX4, RX5, RX6, RX7, RX8, RX9, RX10, RX11, RX12, RX13
+ * TX1, TX2, TX3, TX4, TX5, TX6, TX7, TX8, TX9, TX10, TX11, TX12, TX13
+ * TX14, TX15, TX16
+ */
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS] = {144, 145, 146, 147, 148, 149,
+ 150, 151, 152, 153, 154, 155, 156};
+ unsigned int tx_ch[SLIM_MAX_TX_PORTS] = {128, 129, 130, 131, 132, 133,
+ 134, 135, 136, 137, 138, 139,
+ 140, 141, 142, 143};
+
+ snd_soc_dai_set_channel_map(codec_dai, ARRAY_SIZE(tx_ch),
+ tx_ch, ARRAY_SIZE(rx_ch), rx_ch);
+
+ snd_soc_dai_set_sysclk(codec_dai, 0, WCD9335_DEFAULT_MCLK_RATE,
+ SNDRV_PCM_STREAM_PLAYBACK);
+
+ return 0;
+}
+
static void apq8096_add_be_ops(struct snd_soc_card *card)
{
- struct snd_soc_dai_link *link = card->dai_link;
- int i, num_links = card->num_links;
+ struct snd_soc_dai_link *link;
+ int i;
- for (i = 0; i < num_links; i++) {
- if (link->no_pcm == 1)
+ for_each_card_prelinks(card, i, link) {
+ if (link->no_pcm == 1) {
link->be_hw_params_fixup = apq8096_be_hw_params_fixup;
- link++;
+ link->init = apq8096_init;
+ link->ops = &apq8096_ops;
+ }
}
}
diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c
index 4715527..6c20bdd 100644
--- a/sound/soc/qcom/common.c
+++ b/sound/soc/qcom/common.c
@@ -14,6 +14,7 @@
struct device *dev = card->dev;
struct snd_soc_dai_link *link;
struct of_phandle_args args;
+ struct snd_soc_dai_link_component *dlc;
int ret, num_links;
ret = snd_soc_of_parse_card_name(card, "model");
@@ -40,10 +41,30 @@
card->num_links = num_links;
link = card->dai_link;
+
for_each_child_of_node(dev->of_node, np) {
+ dlc = devm_kzalloc(dev, 2 * sizeof(*dlc), GFP_KERNEL);
+ if (!dlc)
+ return -ENOMEM;
+
+ link->cpus = &dlc[0];
+ link->platforms = &dlc[1];
+
+ link->num_cpus = 1;
+ link->num_platforms = 1;
+
+ ret = of_property_read_string(np, "link-name", &link->name);
+ if (ret) {
+ dev_err(card->dev, "error getting codec dai_link name\n");
+ goto err;
+ }
+
cpu = of_get_child_by_name(np, "cpu");
+ platform = of_get_child_by_name(np, "platform");
+ codec = of_get_child_by_name(np, "codec");
+
if (!cpu) {
- dev_err(dev, "Can't find cpu DT node\n");
+ dev_err(dev, "%s: Can't find cpu DT node\n", link->name);
ret = -EINVAL;
goto err;
}
@@ -51,59 +72,64 @@
ret = of_parse_phandle_with_args(cpu, "sound-dai",
"#sound-dai-cells", 0, &args);
if (ret) {
- dev_err(card->dev, "error getting cpu phandle\n");
+ dev_err(card->dev, "%s: error getting cpu phandle\n", link->name);
goto err;
}
- link->cpu_of_node = args.np;
+ link->cpus->of_node = args.np;
link->id = args.args[0];
- ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name);
+ ret = snd_soc_of_get_dai_name(cpu, &link->cpus->dai_name);
if (ret) {
- dev_err(card->dev, "error getting cpu dai name\n");
+ dev_err(card->dev, "%s: error getting cpu dai name\n", link->name);
goto err;
}
- platform = of_get_child_by_name(np, "platform");
- codec = of_get_child_by_name(np, "codec");
if (codec && platform) {
- link->platform_of_node = of_parse_phandle(platform,
+ link->platforms->of_node = of_parse_phandle(platform,
"sound-dai",
0);
- if (!link->platform_of_node) {
- dev_err(card->dev, "platform dai not found\n");
+ if (!link->platforms->of_node) {
+ dev_err(card->dev, "%s: platform dai not found\n", link->name);
ret = -EINVAL;
goto err;
}
ret = snd_soc_of_get_dai_link_codecs(dev, codec, link);
if (ret < 0) {
- dev_err(card->dev, "codec dai not found\n");
+ dev_err(card->dev, "%s: codec dai not found\n", link->name);
goto err;
}
link->no_pcm = 1;
link->ignore_pmdown_time = 1;
} else {
- link->platform_of_node = link->cpu_of_node;
- link->codec_dai_name = "snd-soc-dummy-dai";
- link->codec_name = "snd-soc-dummy";
+ dlc = devm_kzalloc(dev, sizeof(*dlc), GFP_KERNEL);
+ if (!dlc)
+ return -ENOMEM;
+
+ link->codecs = dlc;
+ link->num_codecs = 1;
+
+ link->platforms->of_node = link->cpus->of_node;
+ link->codecs->dai_name = "snd-soc-dummy-dai";
+ link->codecs->name = "snd-soc-dummy";
link->dynamic = 1;
}
link->ignore_suspend = 1;
- ret = of_property_read_string(np, "link-name", &link->name);
- if (ret) {
- dev_err(card->dev, "error getting codec dai_link name\n");
- goto err;
- }
-
+ link->nonatomic = 1;
link->dpcm_playback = 1;
link->dpcm_capture = 1;
link->stream_name = link->name;
link++;
+
+ of_node_put(cpu);
+ of_node_put(codec);
+ of_node_put(platform);
}
return 0;
err:
+ of_node_put(np);
of_node_put(cpu);
of_node_put(codec);
of_node_put(platform);
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index 8a74844..6575da5 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -1,17 +1,8 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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
- *
*/
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 292b103..dbce7e9 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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-cpu.c -- ALSA SoC CPU DAI driver for QTi LPASS
*/
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index ca1e1f2..1987605 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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
*/
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 2240bc6..3d74ae1 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -1,14 +1,6 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 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__
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index d07271e..4c745ba 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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-platform.c -- ALSA SoC platform driver for QTi LPASS
*/
@@ -91,7 +83,7 @@
if (ret) {
dev_err(soc_runtime->dev,
"error writing to rdmactl reg: %d\n", ret);
- return ret;
+ return ret;
}
data->dma_ch = dma_ch;
@@ -572,11 +564,8 @@
int ret;
drvdata->lpaif_irq = platform_get_irq_byname(pdev, "lpass-irq-lpaif");
- if (drvdata->lpaif_irq < 0) {
- dev_err(&pdev->dev, "error getting irq handle: %d\n",
- drvdata->lpaif_irq);
+ if (drvdata->lpaif_irq < 0)
return -ENODEV;
- }
/* ensure audio hardware is disabled */
ret = regmap_write(drvdata->lpaif_map,
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index b848db2..17113d3 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -1,15 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
/*
* 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.h - Definitions for the QTi LPASS
*/
diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile
index c33b3ca..7e91e96 100644
--- a/sound/soc/qcom/qdsp6/Makefile
+++ b/sound/soc/qcom/qdsp6/Makefile
@@ -1,3 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o
obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o
obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o
diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c
index 932c3eb..da24251 100644
--- a/sound/soc/qcom/qdsp6/q6adm.c
+++ b/sound/soc/qcom/qdsp6/q6adm.c
@@ -2,25 +2,24 @@
// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved.
// Copyright (c) 2018, Linaro Limited
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/kernel.h>
#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_platform.h>
-#include <linux/kref.h>
-#include <linux/wait.h>
-#include <linux/soc/qcom/apr.h>
#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/soc/qcom/apr.h>
+#include <linux/wait.h>
#include <sound/asound.h>
#include "q6adm.h"
#include "q6afe.h"
#include "q6core.h"
-#include "q6dsp-errno.h"
#include "q6dsp-common.h"
+#include "q6dsp-errno.h"
#define ADM_CMD_DEVICE_OPEN_V5 0x00010326
#define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329
diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c
index 8f6c8fc..c1a7624 100644
--- a/sound/soc/qcom/qdsp6/q6afe-dai.c
+++ b/sound/soc/qcom/qdsp6/q6afe-dai.c
@@ -341,6 +341,7 @@
switch (dai->id) {
case HDMI_RX:
+ case DISPLAY_PORT_RX:
q6afe_hdmi_port_prepare(dai_data->port[dai->id],
&dai_data->port_config[dai->id].hdmi);
break;
@@ -445,6 +446,8 @@
static const struct snd_soc_dapm_route q6afe_dapm_routes[] = {
{"HDMI Playback", NULL, "HDMI_RX"},
+ {"Display Port Playback", NULL, "DISPLAY_PORT_RX"},
+ {"Slimbus Playback", NULL, "SLIMBUS_0_RX"},
{"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"},
{"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"},
{"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"},
@@ -561,13 +564,13 @@
{"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"},
};
-static struct snd_soc_dai_ops q6hdmi_ops = {
+static const struct snd_soc_dai_ops q6hdmi_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6hdmi_hw_params,
.shutdown = q6afe_dai_shutdown,
};
-static struct snd_soc_dai_ops q6i2s_ops = {
+static const struct snd_soc_dai_ops q6i2s_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6i2s_hw_params,
.set_fmt = q6i2s_set_fmt,
@@ -575,14 +578,14 @@
.set_sysclk = q6afe_mi2s_set_sysclk,
};
-static struct snd_soc_dai_ops q6slim_ops = {
+static const struct snd_soc_dai_ops q6slim_ops = {
.prepare = q6afe_dai_prepare,
.hw_params = q6slim_hw_params,
.shutdown = q6afe_dai_shutdown,
.set_channel_map = q6slim_set_channel_map,
};
-static struct snd_soc_dai_ops q6tdm_ops = {
+static const struct snd_soc_dai_ops q6tdm_ops = {
.prepare = q6afe_dai_prepare,
.shutdown = q6afe_dai_shutdown,
.set_sysclk = q6afe_mi2s_set_sysclk,
@@ -1090,6 +1093,25 @@
Q6AFE_TDM_CAP_DAI("Quinary", 5, QUINARY_TDM_TX_5),
Q6AFE_TDM_CAP_DAI("Quinary", 6, QUINARY_TDM_TX_6),
Q6AFE_TDM_CAP_DAI("Quinary", 7, QUINARY_TDM_TX_7),
+ {
+ .playback = {
+ .stream_name = "Display Port Playback",
+ .rates = SNDRV_PCM_RATE_48000 |
+ SNDRV_PCM_RATE_96000 |
+ SNDRV_PCM_RATE_192000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE |
+ SNDRV_PCM_FMTBIT_S24_LE,
+ .channels_min = 2,
+ .channels_max = 8,
+ .rate_max = 192000,
+ .rate_min = 48000,
+ },
+ .ops = &q6hdmi_ops,
+ .id = DISPLAY_PORT_RX,
+ .name = "DISPLAY_PORT",
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+ },
};
static int q6afe_of_xlate_dai_name(struct snd_soc_component *component,
@@ -1311,6 +1333,7 @@
0, 0, 0, 0),
SND_SOC_DAPM_AIF_OUT("QUIN_TDM_TX_7", NULL,
0, 0, 0, 0),
+ SND_SOC_DAPM_AIF_OUT("DISPLAY_PORT_RX", "NULL", 0, 0, 0, 0),
};
static const struct snd_soc_component_driver q6afe_dai_component = {
diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c
index 829b5e9..e0945f7 100644
--- a/sound/soc/qcom/qdsp6/q6afe.c
+++ b/sound/soc/qcom/qdsp6/q6afe.c
@@ -71,6 +71,7 @@
/* Port IDs */
#define AFE_API_VERSION_HDMI_CONFIG 0x1
#define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E
+#define AFE_PORT_ID_HDMI_OVER_DP_RX 0x6020
#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1
/* Clock set API version */
@@ -704,6 +705,8 @@
QUINARY_TDM_RX_7, 1, 1},
[QUINARY_TDM_TX_7] = { AFE_PORT_ID_QUINARY_TDM_TX_7,
QUINARY_TDM_TX_7, 0, 1},
+ [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX,
+ DISPLAY_PORT_RX, 1, 1},
};
static void q6afe_port_free(struct kref *ref)
@@ -1384,6 +1387,7 @@
switch (port_id) {
case AFE_PORT_ID_MULTICHAN_HDMI_RX:
+ case AFE_PORT_ID_HDMI_OVER_DP_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
break;
case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX:
diff --git a/sound/soc/qcom/qdsp6/q6asm-dai.c b/sound/soc/qcom/qdsp6/q6asm-dai.c
index 9db9a29..548eb4f 100644
--- a/sound/soc/qcom/qdsp6/q6asm-dai.c
+++ b/sound/soc/qcom/qdsp6/q6asm-dai.c
@@ -8,9 +8,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
-#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm.h>
+#include <linux/spinlock.h>
+#include <sound/compress_driver.h>
#include <asm/dma.h>
#include <linux/dma-mapping.h>
#include <linux/of_device.h>
@@ -31,6 +32,15 @@
#define CAPTURE_MIN_PERIOD_SIZE 320
#define SID_MASK_DEFAULT 0xF
+/* Default values used if user space does not set */
+#define COMPR_PLAYBACK_MIN_FRAGMENT_SIZE (8 * 1024)
+#define COMPR_PLAYBACK_MAX_FRAGMENT_SIZE (128 * 1024)
+#define COMPR_PLAYBACK_MIN_NUM_FRAGMENTS (4)
+#define COMPR_PLAYBACK_MAX_NUM_FRAGMENTS (16 * 4)
+#define Q6ASM_DAI_TX_RX 0
+#define Q6ASM_DAI_TX 1
+#define Q6ASM_DAI_RX 2
+
enum stream_state {
Q6ASM_STREAM_IDLE = 0,
Q6ASM_STREAM_STOPPED,
@@ -39,11 +49,18 @@
struct q6asm_dai_rtd {
struct snd_pcm_substream *substream;
+ struct snd_compr_stream *cstream;
+ struct snd_compr_params codec_param;
+ struct snd_dma_buffer dma_buffer;
+ spinlock_t lock;
phys_addr_t phys;
unsigned int pcm_size;
unsigned int pcm_count;
unsigned int pcm_irq_pos; /* IRQ position */
unsigned int periods;
+ unsigned int bytes_sent;
+ unsigned int bytes_received;
+ unsigned int copied_total;
uint16_t bits_per_sample;
uint16_t source; /* Encoding source bit mask */
struct audio_client *audio_client;
@@ -123,7 +140,6 @@
.rate_max = 48000, \
}, \
.name = "MultiMedia"#num, \
- .probe = fe_dai_probe, \
.id = MSM_FRONTEND_DAI_MULTIMEDIA##num, \
}
@@ -139,6 +155,21 @@
.mask = 0,
};
+static const struct snd_compr_codec_caps q6asm_compr_caps = {
+ .num_descriptors = 1,
+ .descriptor[0].max_ch = 2,
+ .descriptor[0].sample_rates = { 8000, 11025, 12000, 16000, 22050,
+ 24000, 32000, 44100, 48000, 88200,
+ 96000, 176400, 192000 },
+ .descriptor[0].num_sample_rates = 13,
+ .descriptor[0].bit_rate[0] = 320,
+ .descriptor[0].bit_rate[1] = 128,
+ .descriptor[0].num_bitrates = 2,
+ .descriptor[0].profiles = 0,
+ .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+ .descriptor[0].formats = 0,
+};
+
static void event_handler(uint32_t opcode, uint32_t token,
uint32_t *payload, void *priv)
{
@@ -319,10 +350,11 @@
prtd->audio_client = q6asm_audio_client_alloc(dev,
(q6asm_cb)event_handler, prtd, stream_id,
LEGACY_PCM_MODE);
- if (!prtd->audio_client) {
+ if (IS_ERR(prtd->audio_client)) {
pr_info("%s: Could not allocate memory\n", __func__);
+ ret = PTR_ERR(prtd->audio_client);
kfree(prtd);
- return -ENOMEM;
+ return ret;
}
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
@@ -461,6 +493,313 @@
.mmap = q6asm_dai_mmap,
};
+static void compress_event_handler(uint32_t opcode, uint32_t token,
+ uint32_t *payload, void *priv)
+{
+ struct q6asm_dai_rtd *prtd = priv;
+ struct snd_compr_stream *substream = prtd->cstream;
+ unsigned long flags;
+ uint64_t avail;
+
+ switch (opcode) {
+ case ASM_CLIENT_EVENT_CMD_RUN_DONE:
+ spin_lock_irqsave(&prtd->lock, flags);
+ if (!prtd->bytes_sent) {
+ q6asm_write_async(prtd->audio_client, prtd->pcm_count,
+ 0, 0, NO_TIMESTAMP);
+ prtd->bytes_sent += prtd->pcm_count;
+ }
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
+ case ASM_CLIENT_EVENT_CMD_EOS_DONE:
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ break;
+
+ case ASM_CLIENT_EVENT_DATA_WRITE_DONE:
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ prtd->copied_total += prtd->pcm_count;
+ snd_compr_fragment_elapsed(substream);
+
+ if (prtd->state != Q6ASM_STREAM_RUNNING) {
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+ }
+
+ avail = prtd->bytes_received - prtd->bytes_sent;
+
+ if (avail >= prtd->pcm_count) {
+ q6asm_write_async(prtd->audio_client,
+ prtd->pcm_count, 0, 0, NO_TIMESTAMP);
+ prtd->bytes_sent += prtd->pcm_count;
+ }
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int q6asm_dai_compr_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ struct q6asm_dai_rtd *prtd;
+ int stream_id, size, ret;
+
+ stream_id = cpu_dai->driver->id;
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata) {
+ dev_err(dev, "Drv data not found ..\n");
+ return -EINVAL;
+ }
+
+ prtd = kzalloc(sizeof(*prtd), GFP_KERNEL);
+ if (!prtd)
+ return -ENOMEM;
+
+ prtd->cstream = stream;
+ prtd->audio_client = q6asm_audio_client_alloc(dev,
+ (q6asm_cb)compress_event_handler,
+ prtd, stream_id, LEGACY_PCM_MODE);
+ if (IS_ERR(prtd->audio_client)) {
+ dev_err(dev, "Could not allocate memory\n");
+ ret = PTR_ERR(prtd->audio_client);
+ goto free_prtd;
+ }
+
+ size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE *
+ COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ ret = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, dev, size,
+ &prtd->dma_buffer);
+ if (ret) {
+ dev_err(dev, "Cannot allocate buffer(s)\n");
+ goto free_client;
+ }
+
+ if (pdata->sid < 0)
+ prtd->phys = prtd->dma_buffer.addr;
+ else
+ prtd->phys = prtd->dma_buffer.addr | (pdata->sid << 32);
+
+ snd_compr_set_runtime_buffer(stream, &prtd->dma_buffer);
+ spin_lock_init(&prtd->lock);
+ runtime->private_data = prtd;
+
+ return 0;
+
+free_client:
+ q6asm_audio_client_free(prtd->audio_client);
+free_prtd:
+ kfree(prtd);
+
+ return ret;
+}
+
+static int q6asm_dai_compr_free(struct snd_compr_stream *stream)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+
+ if (prtd->audio_client) {
+ if (prtd->state)
+ q6asm_cmd(prtd->audio_client, CMD_CLOSE);
+
+ snd_dma_free_pages(&prtd->dma_buffer);
+ q6asm_unmap_memory_regions(stream->direction,
+ prtd->audio_client);
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ }
+ q6routing_stream_close(rtd->dai_link->id, stream->direction);
+ kfree(prtd);
+
+ return 0;
+}
+
+static int q6asm_dai_compr_set_params(struct snd_compr_stream *stream,
+ struct snd_compr_params *params)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ int dir = stream->direction;
+ struct q6asm_dai_data *pdata;
+ struct device *dev = c->dev;
+ int ret;
+
+ memcpy(&prtd->codec_param, params, sizeof(*params));
+
+ pdata = snd_soc_component_get_drvdata(c);
+ if (!pdata)
+ return -EINVAL;
+
+ if (!prtd || !prtd->audio_client) {
+ dev_err(dev, "private data null or audio client freed\n");
+ return -EINVAL;
+ }
+
+ prtd->periods = runtime->fragments;
+ prtd->pcm_count = runtime->fragment_size;
+ prtd->pcm_size = runtime->fragments * runtime->fragment_size;
+ prtd->bits_per_sample = 16;
+ if (dir == SND_COMPRESS_PLAYBACK) {
+ ret = q6asm_open_write(prtd->audio_client, params->codec.id,
+ prtd->bits_per_sample);
+
+ if (ret < 0) {
+ dev_err(dev, "q6asm_open_write failed\n");
+ q6asm_audio_client_free(prtd->audio_client);
+ prtd->audio_client = NULL;
+ return ret;
+ }
+ }
+
+ prtd->session_id = q6asm_get_session_id(prtd->audio_client);
+ ret = q6routing_stream_open(rtd->dai_link->id, LEGACY_PCM_MODE,
+ prtd->session_id, dir);
+ if (ret) {
+ dev_err(dev, "Stream reg failed ret:%d\n", ret);
+ return ret;
+ }
+
+ ret = q6asm_map_memory_regions(dir, prtd->audio_client, prtd->phys,
+ (prtd->pcm_size / prtd->periods),
+ prtd->periods);
+
+ if (ret < 0) {
+ dev_err(dev, "Buffer Mapping failed ret:%d\n", ret);
+ return -ENOMEM;
+ }
+
+ prtd->state = Q6ASM_STREAM_RUNNING;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_trigger(struct snd_compr_stream *stream, int cmd)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ int ret = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ ret = q6asm_run_nowait(prtd->audio_client, 0, 0, 0);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ prtd->state = Q6ASM_STREAM_STOPPED;
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_EOS);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ret = q6asm_cmd_nowait(prtd->audio_client, CMD_PAUSE);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int q6asm_dai_compr_pointer(struct snd_compr_stream *stream,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prtd->lock, flags);
+
+ tstamp->copied_total = prtd->copied_total;
+ tstamp->byte_offset = prtd->copied_total % prtd->pcm_size;
+
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ return 0;
+}
+
+static int q6asm_dai_compr_ack(struct snd_compr_stream *stream,
+ size_t count)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&prtd->lock, flags);
+ prtd->bytes_received += count;
+ spin_unlock_irqrestore(&prtd->lock, flags);
+
+ return count;
+}
+
+static int q6asm_dai_compr_mmap(struct snd_compr_stream *stream,
+ struct vm_area_struct *vma)
+{
+ struct snd_compr_runtime *runtime = stream->runtime;
+ struct q6asm_dai_rtd *prtd = runtime->private_data;
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME);
+ struct device *dev = c->dev;
+
+ return dma_mmap_coherent(dev, vma,
+ prtd->dma_buffer.area, prtd->dma_buffer.addr,
+ prtd->dma_buffer.bytes);
+}
+
+static int q6asm_dai_compr_get_caps(struct snd_compr_stream *stream,
+ struct snd_compr_caps *caps)
+{
+ caps->direction = SND_COMPRESS_PLAYBACK;
+ caps->min_fragment_size = COMPR_PLAYBACK_MIN_FRAGMENT_SIZE;
+ caps->max_fragment_size = COMPR_PLAYBACK_MAX_FRAGMENT_SIZE;
+ caps->min_fragments = COMPR_PLAYBACK_MIN_NUM_FRAGMENTS;
+ caps->max_fragments = COMPR_PLAYBACK_MAX_NUM_FRAGMENTS;
+ caps->num_codecs = 1;
+ caps->codecs[0] = SND_AUDIOCODEC_MP3;
+
+ return 0;
+}
+
+static int q6asm_dai_compr_get_codec_caps(struct snd_compr_stream *stream,
+ struct snd_compr_codec_caps *codec)
+{
+ switch (codec->codec) {
+ case SND_AUDIOCODEC_MP3:
+ *codec = q6asm_compr_caps;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static struct snd_compr_ops q6asm_dai_compr_ops = {
+ .open = q6asm_dai_compr_open,
+ .free = q6asm_dai_compr_free,
+ .set_params = q6asm_dai_compr_set_params,
+ .pointer = q6asm_dai_compr_pointer,
+ .trigger = q6asm_dai_compr_trigger,
+ .get_caps = q6asm_dai_compr_get_caps,
+ .get_codec_caps = q6asm_dai_compr_get_codec_caps,
+ .mmap = q6asm_dai_compr_mmap,
+ .ack = q6asm_dai_compr_ack,
+};
+
static int q6asm_dai_pcm_new(struct snd_soc_pcm_runtime *rtd)
{
struct snd_pcm_substream *psubstream, *csubstream;
@@ -493,7 +832,7 @@
}
}
- return ret;
+ return 0;
}
static void q6asm_dai_pcm_free(struct snd_pcm *pcm)
@@ -511,44 +850,12 @@
}
}
-static const struct snd_soc_dapm_route afe_pcm_routes[] = {
- {"MM_DL1", NULL, "MultiMedia1 Playback" },
- {"MM_DL2", NULL, "MultiMedia2 Playback" },
- {"MM_DL3", NULL, "MultiMedia3 Playback" },
- {"MM_DL4", NULL, "MultiMedia4 Playback" },
- {"MM_DL5", NULL, "MultiMedia5 Playback" },
- {"MM_DL6", NULL, "MultiMedia6 Playback" },
- {"MM_DL7", NULL, "MultiMedia7 Playback" },
- {"MM_DL7", NULL, "MultiMedia8 Playback" },
- {"MultiMedia1 Capture", NULL, "MM_UL1"},
- {"MultiMedia2 Capture", NULL, "MM_UL2"},
- {"MultiMedia3 Capture", NULL, "MM_UL3"},
- {"MultiMedia4 Capture", NULL, "MM_UL4"},
- {"MultiMedia5 Capture", NULL, "MM_UL5"},
- {"MultiMedia6 Capture", NULL, "MM_UL6"},
- {"MultiMedia7 Capture", NULL, "MM_UL7"},
- {"MultiMedia8 Capture", NULL, "MM_UL8"},
-
-};
-
-static int fe_dai_probe(struct snd_soc_dai *dai)
-{
- struct snd_soc_dapm_context *dapm;
-
- dapm = snd_soc_component_get_dapm(dai->component);
- snd_soc_dapm_add_routes(dapm, afe_pcm_routes,
- ARRAY_SIZE(afe_pcm_routes));
-
- return 0;
-}
-
-
static const struct snd_soc_component_driver q6asm_fe_dai_component = {
.name = DRV_NAME,
.ops = &q6asm_dai_ops,
.pcm_new = q6asm_dai_pcm_new,
.pcm_free = q6asm_dai_pcm_free,
-
+ .compr_ops = &q6asm_dai_compr_ops,
};
static struct snd_soc_dai_driver q6asm_fe_dais[] = {
@@ -562,6 +869,41 @@
Q6ASM_FEDAI_DRIVER(8),
};
+static int of_q6asm_parse_dai_data(struct device *dev,
+ struct q6asm_dai_data *pdata)
+{
+ static struct snd_soc_dai_driver *dai_drv;
+ struct snd_soc_pcm_stream empty_stream;
+ struct device_node *node;
+ int ret, id, dir;
+
+ memset(&empty_stream, 0, sizeof(empty_stream));
+
+ for_each_child_of_node(dev->of_node, node) {
+ ret = of_property_read_u32(node, "reg", &id);
+ if (ret || id >= MAX_SESSIONS || id < 0) {
+ dev_err(dev, "valid dai id not found:%d\n", ret);
+ continue;
+ }
+
+ dai_drv = &q6asm_fe_dais[id];
+
+ ret = of_property_read_u32(node, "direction", &dir);
+ if (ret)
+ continue;
+
+ if (dir == Q6ASM_DAI_RX)
+ dai_drv->capture = empty_stream;
+ else if (dir == Q6ASM_DAI_TX)
+ dai_drv->playback = empty_stream;
+
+ if (of_property_read_bool(node, "is-compress-dai"))
+ dai_drv->compress_new = snd_soc_new_compress;
+ }
+
+ return 0;
+}
+
static int q6asm_dai_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -582,6 +924,8 @@
dev_set_drvdata(dev, pdata);
+ of_q6asm_parse_dai_data(dev, pdata);
+
return devm_snd_soc_register_component(dev, &q6asm_fe_dai_component,
q6asm_fe_dais,
ARRAY_SIZE(q6asm_fe_dais));
diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c
index 2b2c723..e8141a3 100644
--- a/sound/soc/qcom/qdsp6/q6asm.c
+++ b/sound/soc/qcom/qdsp6/q6asm.c
@@ -11,8 +11,8 @@
#include <linux/spinlock.h>
#include <linux/kref.h>
#include <linux/of.h>
-#include <linux/of_platform.h>
#include <uapi/sound/asound.h>
+#include <uapi/sound/compress_params.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/mm.h>
@@ -37,6 +37,7 @@
#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3
#define ASM_SESSION_CMD_RUN_V2 0x00010DAA
#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5
+#define ASM_MEDIA_FMT_MP3 0x00010BE9
#define ASM_DATA_CMD_WRITE_V2 0x00010DAB
#define ASM_DATA_CMD_READ_V2 0x00010DAC
#define ASM_SESSION_CMD_SUSPEND 0x00010DEC
@@ -869,6 +870,9 @@
open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY;
switch (format) {
+ case SND_AUDIOCODEC_MP3:
+ open->dec_fmt_id = ASM_MEDIA_FMT_MP3;
+ break;
case FORMAT_LINEAR_PCM:
open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2;
break;
@@ -1190,7 +1194,7 @@
* q6asm_write_async() - non blocking write
*
* @ac: audio client pointer
- * @len: lenght in bytes
+ * @len: length in bytes
* @msw_ts: timestamp msw
* @lsw_ts: timestamp lsw
* @wflags: flags associated with write
diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c
index 06f03a5..ae314a6 100644
--- a/sound/soc/qcom/qdsp6/q6core.c
+++ b/sound/soc/qcom/qdsp6/q6core.c
@@ -10,7 +10,6 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/jiffies.h>
-#include <linux/wait.h>
#include <linux/soc/qcom/apr.h>
#include "q6core.h"
#include "q6dsp-errno.h"
@@ -99,18 +98,16 @@
}
case AVCS_CMDRSP_GET_FWK_VERSION: {
struct avcs_cmdrsp_get_fwk_version *fwk;
- int bytes;
fwk = data->payload;
- bytes = sizeof(*fwk) + fwk->num_services *
- sizeof(fwk->svc_api_info[0]);
- core->fwk_version = kzalloc(bytes, GFP_ATOMIC);
+ core->fwk_version = kmemdup(data->payload,
+ struct_size(fwk, svc_api_info,
+ fwk->num_services),
+ GFP_ATOMIC);
if (!core->fwk_version)
return -ENOMEM;
- memcpy(core->fwk_version, data->payload, bytes);
-
core->fwk_version_supported = true;
core->resp_received = true;
@@ -118,18 +115,16 @@
}
case AVCS_GET_VERSIONS_RSP: {
struct avcs_cmdrsp_get_version *v;
- int len;
v = data->payload;
- len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]);
-
- core->svc_version = kzalloc(len, GFP_ATOMIC);
+ core->svc_version = kmemdup(data->payload,
+ struct_size(v, svc_api_info,
+ v->num_services),
+ GFP_ATOMIC);
if (!core->svc_version)
return -ENOMEM;
- memcpy(core->svc_version, data->payload, len);
-
core->get_version_supported = true;
core->resp_received = true;
diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c
index c6b5157..ddcd997 100644
--- a/sound/soc/qcom/qdsp6/q6routing.c
+++ b/sound/soc/qcom/qdsp6/q6routing.c
@@ -453,6 +453,9 @@
static const struct snd_kcontrol_new hdmi_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(HDMI_RX) };
+static const struct snd_kcontrol_new display_port_mixer_controls[] = {
+ Q6ROUTING_RX_MIXERS(DISPLAY_PORT_RX) };
+
static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = {
Q6ROUTING_RX_MIXERS(PRIMARY_MI2S_RX) };
@@ -655,6 +658,10 @@
hdmi_mixer_controls,
ARRAY_SIZE(hdmi_mixer_controls)),
+ SND_SOC_DAPM_MIXER("DISPLAY_PORT_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
+ display_port_mixer_controls,
+ ARRAY_SIZE(display_port_mixer_controls)),
+
SND_SOC_DAPM_MIXER("SLIMBUS_0_RX Audio Mixer", SND_SOC_NOPM, 0, 0,
slimbus_rx_mixer_controls,
ARRAY_SIZE(slimbus_rx_mixer_controls)),
@@ -833,6 +840,8 @@
static const struct snd_soc_dapm_route intercon[] = {
Q6ROUTING_RX_DAPM_ROUTE("HDMI Mixer", "HDMI_RX"),
+ Q6ROUTING_RX_DAPM_ROUTE("DISPLAY_PORT_RX Audio Mixer",
+ "DISPLAY_PORT_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_0_RX Audio Mixer", "SLIMBUS_0_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_1_RX Audio Mixer", "SLIMBUS_1_RX"),
Q6ROUTING_RX_DAPM_ROUTE("SLIMBUS_2_RX Audio Mixer", "SLIMBUS_2_RX"),
@@ -909,6 +918,25 @@
{"MM_UL6", NULL, "MultiMedia6 Mixer"},
{"MM_UL7", NULL, "MultiMedia7 Mixer"},
{"MM_UL8", NULL, "MultiMedia8 Mixer"},
+
+ {"MM_DL1", NULL, "MultiMedia1 Playback" },
+ {"MM_DL2", NULL, "MultiMedia2 Playback" },
+ {"MM_DL3", NULL, "MultiMedia3 Playback" },
+ {"MM_DL4", NULL, "MultiMedia4 Playback" },
+ {"MM_DL5", NULL, "MultiMedia5 Playback" },
+ {"MM_DL6", NULL, "MultiMedia6 Playback" },
+ {"MM_DL7", NULL, "MultiMedia7 Playback" },
+ {"MM_DL8", NULL, "MultiMedia8 Playback" },
+
+ {"MultiMedia1 Capture", NULL, "MM_UL1"},
+ {"MultiMedia2 Capture", NULL, "MM_UL2"},
+ {"MultiMedia3 Capture", NULL, "MM_UL3"},
+ {"MultiMedia4 Capture", NULL, "MM_UL4"},
+ {"MultiMedia5 Capture", NULL, "MM_UL5"},
+ {"MultiMedia6 Capture", NULL, "MM_UL6"},
+ {"MultiMedia7 Capture", NULL, "MM_UL7"},
+ {"MultiMedia8 Capture", NULL, "MM_UL8"},
+
};
static int routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/qcom/sdm845.c b/sound/soc/qcom/sdm845.c
index 2a781d8..28f3cef 100644
--- a/sound/soc/qcom/sdm845.c
+++ b/sound/soc/qcom/sdm845.c
@@ -6,18 +6,31 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of_device.h>
+#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+#include <uapi/linux/input-event-codes.h>
#include "common.h"
#include "qdsp6/q6afe.h"
+#include "../codecs/rt5663.h"
#define DEFAULT_SAMPLE_RATE_48K 48000
#define DEFAULT_MCLK_RATE 24576000
-#define DEFAULT_BCLK_RATE 12288000
+#define TDM_BCLK_RATE 6144000
+#define MI2S_BCLK_RATE 1536000
+#define LEFT_SPK_TDM_TX_MASK 0x30
+#define RIGHT_SPK_TDM_TX_MASK 0xC0
+#define SPK_TDM_RX_MASK 0x03
+#define NUM_TDM_SLOTS 8
struct sdm845_snd_data {
+ struct snd_soc_jack jack;
+ bool jack_setup;
struct snd_soc_card *card;
uint32_t pri_mi2s_clk_count;
+ uint32_t sec_mi2s_clk_count;
uint32_t quat_tdm_clk_count;
};
@@ -28,12 +41,12 @@
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
- int ret = 0;
+ int ret = 0, j;
int channels, slot_width;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
- slot_width = 32;
+ slot_width = 16;
break;
default:
dev_err(rtd->dev, "%s: invalid param format 0x%x\n",
@@ -75,6 +88,35 @@
goto end;
}
}
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ struct snd_soc_dai *codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name_prefix, "Left")) {
+ ret = snd_soc_dai_set_tdm_slot(
+ codec_dai, LEFT_SPK_TDM_TX_MASK,
+ SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+ slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "DEV0 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!strcmp(codec_dai->component->name_prefix, "Right")) {
+ ret = snd_soc_dai_set_tdm_slot(
+ codec_dai, RIGHT_SPK_TDM_TX_MASK,
+ SPK_TDM_RX_MASK, NUM_TDM_SLOTS,
+ slot_width);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "DEV1 TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
+ }
+
end:
return ret;
}
@@ -84,9 +126,27 @@
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
int ret = 0;
switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ case PRIMARY_MI2S_TX:
+ /*
+ * Use ASRC for internal clocks, as PLL rate isn't multiple
+ * of BCLK.
+ */
+ rt5663_sel_asrc_clk_src(
+ codec_dai->component,
+ RT5663_DA_STEREO_FILTER | RT5663_AD_STEREO_FILTER,
+ RT5663_CLK_SEL_I2S1_ASRC);
+ ret = snd_soc_dai_set_sysclk(
+ codec_dai, RT5663_SCLK_S_MCLK, DEFAULT_MCLK_RATE,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ dev_err(rtd->dev,
+ "snd_soc_dai_set_sysclk err = %d\n", ret);
+ break;
case QUATERNARY_TDM_RX_0:
case QUATERNARY_TDM_TX_0:
ret = sdm845_tdm_snd_hw_params(substream, params);
@@ -98,26 +158,104 @@
return ret;
}
+static void sdm845_jack_free(struct snd_jack *jack)
+{
+ struct snd_soc_component *component = jack->private_data;
+
+ snd_soc_component_set_jack(component, NULL, NULL);
+}
+
+static int sdm845_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_component *component;
+ struct snd_soc_card *card = rtd->card;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct sdm845_snd_data *pdata = snd_soc_card_get_drvdata(card);
+ struct snd_jack *jack;
+ int rval;
+
+ if (!pdata->jack_setup) {
+ rval = snd_soc_card_jack_new(card, "Headset Jack",
+ SND_JACK_HEADSET |
+ SND_JACK_HEADPHONE |
+ SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+ SND_JACK_BTN_2 | SND_JACK_BTN_3,
+ &pdata->jack, NULL, 0);
+
+ if (rval < 0) {
+ dev_err(card->dev, "Unable to add Headphone Jack\n");
+ return rval;
+ }
+
+ jack = pdata->jack.jack;
+
+ snd_jack_set_key(jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
+ snd_jack_set_key(jack, SND_JACK_BTN_1, KEY_VOICECOMMAND);
+ snd_jack_set_key(jack, SND_JACK_BTN_2, KEY_VOLUMEUP);
+ snd_jack_set_key(jack, SND_JACK_BTN_3, KEY_VOLUMEDOWN);
+ pdata->jack_setup = true;
+ }
+
+ switch (cpu_dai->id) {
+ case PRIMARY_MI2S_RX:
+ jack = pdata->jack.jack;
+ component = codec_dai->component;
+
+ jack->private_data = component;
+ jack->private_free = sdm845_jack_free;
+ rval = snd_soc_component_set_jack(component,
+ &pdata->jack, NULL);
+ if (rval != 0 && rval != -ENOTSUPP) {
+ dev_warn(card->dev, "Failed to set jack: %d\n", rval);
+ return rval;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
static int sdm845_snd_startup(struct snd_pcm_substream *substream)
{
unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+ unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_card *card = rtd->card;
struct sdm845_snd_data *data = snd_soc_card_get_drvdata(card);
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int j;
+ int ret;
switch (cpu_dai->id) {
case PRIMARY_MI2S_RX:
case PRIMARY_MI2S_TX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF;
if (++(data->pri_mi2s_clk_count) == 1) {
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_MCLK_1,
DEFAULT_MCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
- DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
}
snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
+ break;
+
+ case SECONDARY_MI2S_TX:
+ codec_dai_fmt |= SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S;
+ if (++(data->sec_mi2s_clk_count) == 1) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ MI2S_BCLK_RATE, SNDRV_PCM_STREAM_CAPTURE);
+ }
+ snd_soc_dai_set_fmt(cpu_dai, fmt);
+ snd_soc_dai_set_fmt(codec_dai, codec_dai_fmt);
break;
case QUATERNARY_TDM_RX_0:
@@ -125,7 +263,35 @@
if (++(data->quat_tdm_clk_count) == 1) {
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT,
- DEFAULT_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ TDM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK);
+ }
+
+ codec_dai_fmt |= SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_DSP_B;
+
+ for (j = 0; j < rtd->num_codecs; j++) {
+ codec_dai = rtd->codec_dais[j];
+
+ if (!strcmp(codec_dai->component->name_prefix,
+ "Left")) {
+ ret = snd_soc_dai_set_fmt(
+ codec_dai, codec_dai_fmt);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "Left TDM fmt err:%d\n", ret);
+ return ret;
+ }
+ }
+
+ if (!strcmp(codec_dai->component->name_prefix,
+ "Right")) {
+ ret = snd_soc_dai_set_fmt(
+ codec_dai, codec_dai_fmt);
+ if (ret < 0) {
+ dev_err(rtd->dev,
+ "Right TDM slot err:%d\n", ret);
+ return ret;
+ }
+ }
}
break;
@@ -153,7 +319,15 @@
snd_soc_dai_set_sysclk(cpu_dai,
Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT,
0, SNDRV_PCM_STREAM_PLAYBACK);
- };
+ }
+ break;
+
+ case SECONDARY_MI2S_TX:
+ if (--(data->sec_mi2s_clk_count) == 0) {
+ snd_soc_dai_set_sysclk(cpu_dai,
+ Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT,
+ 0, SNDRV_PCM_STREAM_CAPTURE);
+ }
break;
case QUATERNARY_TDM_RX_0:
@@ -171,7 +345,7 @@
}
}
-static struct snd_soc_ops sdm845_be_ops = {
+static const struct snd_soc_ops sdm845_be_ops = {
.hw_params = sdm845_snd_hw_params,
.startup = sdm845_snd_startup,
.shutdown = sdm845_snd_shutdown,
@@ -193,17 +367,25 @@
return 0;
}
-static void sdm845_add_be_ops(struct snd_soc_card *card)
-{
- struct snd_soc_dai_link *link = card->dai_link;
- int i, num_links = card->num_links;
+static const struct snd_soc_dapm_widget sdm845_snd_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Left Spk", NULL),
+ SND_SOC_DAPM_SPK("Right Spk", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
- for (i = 0; i < num_links; i++) {
+static void sdm845_add_ops(struct snd_soc_card *card)
+{
+ struct snd_soc_dai_link *link;
+ int i;
+
+ for_each_card_prelinks(card, i, link) {
if (link->no_pcm == 1) {
link->ops = &sdm845_be_ops;
link->be_hw_params_fixup = sdm845_be_hw_params_fixup;
}
- link++;
+ link->init = sdm845_dai_init;
}
}
@@ -225,6 +407,8 @@
goto data_alloc_fail;
}
+ card->dapm_widgets = sdm845_snd_widgets;
+ card->num_dapm_widgets = ARRAY_SIZE(sdm845_snd_widgets);
card->dev = dev;
dev_set_drvdata(dev, card);
ret = qcom_snd_parse_of(card);
@@ -236,7 +420,7 @@
data->card = card;
snd_soc_card_set_drvdata(card, data);
- sdm845_add_be_ops(card);
+ sdm845_add_ops(card);
ret = snd_soc_register_card(card);
if (ret) {
dev_err(dev, "Sound card registration failed\n");
diff --git a/sound/soc/qcom/storm.c b/sound/soc/qcom/storm.c
index a9fa972..e6666e5 100644
--- a/sound/soc/qcom/storm.c
+++ b/sound/soc/qcom/storm.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* 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.
- *
* storm.c -- ALSA SoC machine driver for QTi ipq806x-based Storm board
*/
@@ -61,11 +53,16 @@
.hw_params = storm_ops_hw_params,
};
+SND_SOC_DAILINK_DEFS(hifi,
+ DAILINK_COMP_ARRAY(COMP_EMPTY()),
+ DAILINK_COMP_ARRAY(COMP_CODEC(NULL, "HiFi")),
+ DAILINK_COMP_ARRAY(COMP_EMPTY()));
+
static struct snd_soc_dai_link storm_dai_link = {
.name = "Primary",
.stream_name = "Primary",
- .codec_dai_name = "HiFi",
.ops = &storm_soc_ops,
+ SND_SOC_DAILINK_REG(hifi),
};
static int storm_parse_of(struct snd_soc_card *card)
@@ -73,15 +70,15 @@
struct snd_soc_dai_link *dai_link = card->dai_link;
struct device_node *np = card->dev->of_node;
- dai_link->cpu_of_node = of_parse_phandle(np, "cpu", 0);
- if (!dai_link->cpu_of_node) {
+ dai_link->cpus->of_node = of_parse_phandle(np, "cpu", 0);
+ if (!dai_link->cpus->of_node) {
dev_err(card->dev, "error getting cpu phandle\n");
return -EINVAL;
}
- dai_link->platform_of_node = dai_link->cpu_of_node;
+ dai_link->platforms->of_node = dai_link->cpus->of_node;
- dai_link->codec_of_node = of_parse_phandle(np, "codec", 0);
- if (!dai_link->codec_of_node) {
+ dai_link->codecs->of_node = of_parse_phandle(np, "codec", 0);
+ if (!dai_link->codecs->of_node) {
dev_err(card->dev, "error getting codec phandle\n");
return -EINVAL;
}