ASoc: msm: Add support for slimbus shared channel.
Previously, DSP used to setup the data path towards the
codec via slimbus. Now, the data path setup is broken into
two parts - one half of the path setup between apps to slimbus
and the other half from DSP. This configuration mode is
required to reduce overflow or underflow errors. Also this is
required to handle a configuration where mdm can talk
directly to codec.
Change-Id: Ic9f20b8a2f8a8eb355c07565ec80ec947a7a7337
Signed-off-by: Bharath Ramachandramurthy <bramacha@codeaurora.org>
diff --git a/sound/soc/msm/apq8064.c b/sound/soc/msm/apq8064.c
index bd41e0b..b515090 100644
--- a/sound/soc/msm/apq8064.c
+++ b/sound/soc/msm/apq8064.c
@@ -671,6 +671,66 @@
return tabla_cal;
}
+static int msm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+ pr_debug("%s: ch=%d\n", __func__,
+ msm_slim_0_rx_ch);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ msm_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ msm_slim_0_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ msm_slim_0_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+
+
+ }
+end:
+ return ret;
+}
+
static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -924,6 +984,7 @@
static struct snd_soc_ops msm_be_ops = {
.startup = msm_startup,
+ .hw_params = msm_hw_params,
.shutdown = msm_shutdown,
};
diff --git a/sound/soc/msm/msm-dai-q6.c b/sound/soc/msm/msm-dai-q6.c
index 0951795..aff87ae 100644
--- a/sound/soc/msm/msm-dai-q6.c
+++ b/sound/soc/msm/msm-dai-q6.c
@@ -211,81 +211,28 @@
struct snd_soc_dai *dai, int stream)
{
struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
- u8 pgd_la, inf_la;
- u16 *slave_port_mapping;
-
- memset(dai_data->port_config.slimbus.slave_port_mapping, 0,
- sizeof(dai_data->port_config.slimbus.slave_port_mapping));
dai_data->channels = params_channels(params);
-
- slave_port_mapping = dai_data->port_config.slimbus.slave_port_mapping;
-
- switch (dai_data->channels) {
- case 4:
- if (dai->id == SLIMBUS_0_TX) {
- slave_port_mapping[0] = 7;
- slave_port_mapping[1] = 8;
- slave_port_mapping[2] = 9;
- slave_port_mapping[3] = 10;
- } else {
- return -EINVAL;
- }
- break;
- case 3:
- if (dai->id == SLIMBUS_0_TX) {
- slave_port_mapping[0] = 7;
- slave_port_mapping[1] = 8;
- slave_port_mapping[2] = 9;
- } else {
- return -EINVAL;
- }
- break;
- case 2:
- if (dai->id == SLIMBUS_0_RX) {
- slave_port_mapping[0] = 1;
- slave_port_mapping[1] = 2;
- } else {
- slave_port_mapping[0] = 7;
- slave_port_mapping[1] = 8;
- }
- break;
- case 1:
- if (dai->id == SLIMBUS_0_RX)
- slave_port_mapping[0] = 1;
- else
- slave_port_mapping[0] = 7;
- break;
- default:
- return -EINVAL;
- break;
- }
dai_data->rate = params_rate(params);
- tabla_get_logical_addresses(&pgd_la, &inf_la);
dai_data->port_config.slimbus.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1;
- dai_data->port_config.slimbus.slave_dev_pgd_la = pgd_la;
- dai_data->port_config.slimbus.slave_dev_intfdev_la = inf_la;
/* Q6 only supports 16 as now */
- dai_data->port_config.slimbus.bit_width = 16;
- dai_data->port_config.slimbus.data_format = 0;
- dai_data->port_config.slimbus.num_channels = dai_data->channels;
- dai_data->port_config.slimbus.reserved = 0;
+ dai_data->port_config.slim_sch.bit_width = 16;
+ dai_data->port_config.slim_sch.data_format = 0;
+ dai_data->port_config.slim_sch.num_channels = dai_data->channels;
+ dai_data->port_config.slim_sch.reserved = 0;
- dev_dbg(dai->dev, "slimbus_dev_id %hu slave_dev_pgd_la 0x%hx\n"
- "slave_dev_intfdev_la 0x%hx bit_width %hu data_format %hu\n"
- "num_channel %hu slave_port_mapping[0] %hu\n"
+ dev_dbg(dai->dev, "%s:slimbus_dev_id[%hu] bit_wd[%hu] format[%hu]\n"
+ "num_channel %hu slave_ch_mapping[0] %hu\n"
"slave_port_mapping[1] %hu slave_port_mapping[2] %hu\n"
- "sample_rate %d\n",
- dai_data->port_config.slimbus.slimbus_dev_id,
- dai_data->port_config.slimbus.slave_dev_pgd_la,
- dai_data->port_config.slimbus.slave_dev_intfdev_la,
- dai_data->port_config.slimbus.bit_width,
- dai_data->port_config.slimbus.data_format,
- dai_data->port_config.slimbus.num_channels,
- dai_data->port_config.slimbus.slave_port_mapping[0],
- dai_data->port_config.slimbus.slave_port_mapping[1],
- dai_data->port_config.slimbus.slave_port_mapping[2],
+ "sample_rate %d\n", __func__,
+ dai_data->port_config.slim_sch.slimbus_dev_id,
+ dai_data->port_config.slim_sch.bit_width,
+ dai_data->port_config.slim_sch.data_format,
+ dai_data->port_config.slim_sch.num_channels,
+ dai_data->port_config.slim_sch.slave_ch_mapping[0],
+ dai_data->port_config.slim_sch.slave_ch_mapping[1],
+ dai_data->port_config.slim_sch.slave_ch_mapping[2],
dai_data->rate);
return 0;
@@ -784,7 +731,8 @@
{
int rc = 0;
- dev_dbg(dai->dev, "enter %s, id = %d\n", __func__, dai->id);
+ dev_dbg(dai->dev, "enter %s, id = %d fmt[%d]\n", __func__,
+ dai->id, fmt);
switch (dai->id) {
case PRIMARY_I2S_TX:
case PRIMARY_I2S_RX:
@@ -801,12 +749,69 @@
return rc;
}
+static int msm_dai_q6_set_channel_map(struct snd_soc_dai *dai,
+ unsigned int tx_num, unsigned int *tx_slot,
+ unsigned int rx_num, unsigned int *rx_slot)
+
+{
+ int rc = 0;
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+ unsigned int i = 0;
+
+ dev_dbg(dai->dev, "enter %s, id = %d\n", __func__,
+ dai->id);
+ if (!tx_slot && !rx_slot)
+ return -EINVAL;
+ switch (dai->id) {
+ case SLIMBUS_0_RX:
+ /* channel number to be between 128 and 255. For RX port
+ * use channel numbers from 138 to 144, for TX port
+ * use channel numbers from 128 to 137
+ */
+ for (i = 0; i < rx_num; i++) {
+ dai_data->port_config.slim_sch.slave_ch_mapping[i] =
+ rx_slot[i];
+ pr_debug("%s: find number of channels[%d] ch[%d]\n",
+ __func__, i,
+ rx_slot[i]);
+ }
+ dai_data->port_config.slim_sch.num_channels = rx_num;
+ pr_debug("%s:SLIMBUS_0_RX cnt[%d] ch[%d %d]\n", __func__,
+ rx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
+ dai_data->port_config.slim_sch.slave_ch_mapping[1]);
+
+ break;
+ case SLIMBUS_0_TX:
+ /* channel number to be between 128 and 255. For RX port
+ * use channel numbers from 138 to 144, for TX port
+ * use channel numbers from 128 to 137
+ */
+ for (i = 0; i < tx_num; i++) {
+ dai_data->port_config.slim_sch.slave_ch_mapping[i] =
+ tx_slot[i];
+ pr_debug("%s: find number of channels[%d] ch[%d]\n",
+ __func__, i, tx_slot[i]);
+ }
+ dai_data->port_config.slim_sch.num_channels = tx_num;
+ pr_debug("%s:SLIMBUS_0_TX cnt[%d] ch[%d %d]\n", __func__,
+ tx_num, dai_data->port_config.slim_sch.slave_ch_mapping[0],
+ dai_data->port_config.slim_sch.slave_ch_mapping[1]);
+ break;
+ default:
+ dev_err(dai->dev, "invalid cpu_dai set_fmt\n");
+ rc = -EINVAL;
+ break;
+ }
+ return rc;
+}
+
static struct snd_soc_dai_ops msm_dai_q6_ops = {
.prepare = msm_dai_q6_prepare,
.trigger = msm_dai_q6_trigger,
.hw_params = msm_dai_q6_hw_params,
.shutdown = msm_dai_q6_shutdown,
.set_fmt = msm_dai_q6_set_fmt,
+ .set_channel_map = msm_dai_q6_set_channel_map,
};
static struct snd_soc_dai_ops msm_dai_q6_auxpcm_ops = {
diff --git a/sound/soc/msm/msm8960.c b/sound/soc/msm/msm8960.c
index 1ed73e2..bedfd68 100644
--- a/sound/soc/msm/msm8960.c
+++ b/sound/soc/msm/msm8960.c
@@ -643,6 +643,66 @@
return tabla_cal;
}
+static int msm8960_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ int ret = 0;
+ unsigned int rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS];
+ unsigned int rx_ch_cnt = 0, tx_ch_cnt = 0;
+
+ pr_debug("%s: ch=%d\n", __func__,
+ msm8960_slim_0_rx_ch);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+
+ ret = snd_soc_dai_set_channel_map(cpu_dai, 0, 0,
+ msm8960_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai, 0, 0,
+ msm8960_slim_0_rx_ch, rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+ } else {
+ ret = snd_soc_dai_get_channel_map(codec_dai,
+ &tx_ch_cnt, tx_ch, &rx_ch_cnt , rx_ch);
+ if (ret < 0) {
+ pr_err("%s: failed to get codec chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(cpu_dai,
+ msm8960_slim_0_tx_ch, tx_ch, 0 , 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set cpu chan map\n", __func__);
+ goto end;
+ }
+ ret = snd_soc_dai_set_channel_map(codec_dai,
+ msm8960_slim_0_tx_ch, tx_ch, 0, 0);
+ if (ret < 0) {
+ pr_err("%s: failed to set codec channel map\n",
+ __func__);
+ goto end;
+ }
+
+
+ }
+end:
+ return ret;
+}
+
static int msm8960_audrx_init(struct snd_soc_pcm_runtime *rtd)
{
int err;
@@ -914,6 +974,7 @@
static struct snd_soc_ops msm8960_be_ops = {
.startup = msm8960_startup,
+ .hw_params = msm8960_hw_params,
.shutdown = msm8960_shutdown,
};
diff --git a/sound/soc/msm/qdsp6/q6afe.c b/sound/soc/msm/qdsp6/q6afe.c
index ef01fb3..59506f1 100644
--- a/sound/soc/msm/qdsp6/q6afe.c
+++ b/sound/soc/msm/qdsp6/q6afe.c
@@ -78,6 +78,7 @@
switch (payload[0]) {
case AFE_PORT_AUDIO_IF_CONFIG:
case AFE_PORT_MULTI_CHAN_HDMI_AUDIO_IF_CONFIG:
+ case AFE_PORT_AUDIO_SLIM_SCH_CONFIG:
case AFE_PORT_CMD_STOP:
case AFE_PORT_CMD_START:
case AFE_PORT_CMD_LOOPBACK:
@@ -285,7 +286,7 @@
break;
case SLIMBUS_0_RX:
case SLIMBUS_0_TX:
- ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_cfg);
+ ret_size = SIZEOF_CFG_CMD(afe_port_slimbus_sch_cfg);
break;
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
@@ -418,7 +419,23 @@
config.hdr.src_port = 0;
config.hdr.dest_port = 0;
config.hdr.token = 0;
- config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+ switch (port_id) {
+ case SLIMBUS_0_RX:
+ case SLIMBUS_0_TX:
+ case SLIMBUS_1_RX:
+ case SLIMBUS_1_TX:
+ case SLIMBUS_2_RX:
+ case SLIMBUS_2_TX:
+ case SLIMBUS_3_RX:
+ case SLIMBUS_3_TX:
+ case SLIMBUS_4_RX:
+ case SLIMBUS_4_TX:
+ config.hdr.opcode = AFE_PORT_AUDIO_SLIM_SCH_CONFIG;
+ break;
+ default:
+ config.hdr.opcode = AFE_PORT_AUDIO_IF_CONFIG;
+ break;
+ }
}
if (afe_validate_port(port_id) < 0) {
@@ -485,7 +502,7 @@
return ret;
}
- pr_info("%s: %d %d\n", __func__, port_id, rate);
+ pr_debug("%s: %d %d\n", __func__, port_id, rate);
if ((port_id == RT_PROXY_DAI_001_RX) ||
(port_id == RT_PROXY_DAI_002_TX))
@@ -793,7 +810,7 @@
int ret = 0;
struct afe_pseudoport_start_command start;
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
ret = afe_q6_interface_prepare();
if (ret != 0)
@@ -866,7 +883,7 @@
int ret = 0;
struct afe_pseudoport_stop_command stop;
- pr_info("%s: port_id=%d\n", __func__, port_id);
+ pr_debug("%s: port_id=%d\n", __func__, port_id);
if (this_afe.apr == NULL) {
pr_err("%s: AFE is already closed\n", __func__);