Merge "ASoC: msm: Add incall recording support"
diff --git a/include/sound/apr_audio-v2.h b/include/sound/apr_audio-v2.h
index 9201a0a..3abe85d 100644
--- a/include/sound/apr_audio-v2.h
+++ b/include/sound/apr_audio-v2.h
@@ -1884,6 +1884,67 @@
/* For 32 bit alignment. */
} __packed;
+
+/* This param id is used to configure the Pseudoport interface */
+
+#define AFE_PARAM_ID_PSEUDO_PORT_CONFIG 0x00010219
+
+/* Version information used to handle future additions to the configuration
+ * interface (for backward compatibility).
+ */
+#define AFE_API_VERSION_PSEUDO_PORT_CONFIG 0x1
+
+/* Enumeration for setting the timing_mode parameter to faster than real
+ * time.
+ */
+#define AFE_PSEUDOPORT_TIMING_MODE_FTRT 0x0
+
+/* Enumeration for setting the timing_mode parameter to real time using
+ * timers.
+ */
+#define AFE_PSEUDOPORT_TIMING_MODE_TIMER 0x1
+
+/* Payload of the AFE_PARAM_ID_PSEUDO_PORT_CONFIG parameter used by
+ AFE_MODULE_AUDIO_DEV_INTERFACE.
+*/
+struct afe_param_id_pseudo_port_cfg {
+ u32 pseud_port_cfg_minor_version;
+ /*
+ * Minor version used for tracking the version of the pseudoport
+ * configuration interface.
+ */
+
+ u16 bit_width;
+ /* Bit width of the sample at values 16, 24 */
+
+ u16 num_channels;
+ /* Number of channels at values 1 to 8 */
+
+ u16 data_format;
+ /* Non-linear data format supported by the pseudoport (for future use).
+ * At values #AFE_LINEAR_PCM_DATA
+ */
+
+ u16 timing_mode;
+ /* Indicates whether the pseudoport synchronizes to the clock or
+ * operates faster than real time.
+ * at values
+ * - #AFE_PSEUDOPORT_TIMING_MODE_FTRT
+ * - #AFE_PSEUDOPORT_TIMING_MODE_TIMER @tablebulletend
+ */
+
+ u32 sample_rate;
+ /* Sample rate at which the pseudoport will run.
+ * at values
+ * - #AFE_PORT_SAMPLE_RATE_8K
+ * - #AFE_PORT_SAMPLE_RATE_32K
+ * - #AFE_PORT_SAMPLE_RATE_48K
+ * - #AFE_PORT_SAMPLE_RATE_96K
+ * - #AFE_PORT_SAMPLE_RATE_192K @tablebulletend
+ */
+} __packed;
+
+
union afe_port_config {
struct afe_param_id_pcm_cfg pcm;
struct afe_param_id_i2s_cfg i2s;
@@ -1891,6 +1952,7 @@
struct afe_param_id_slimbus_cfg slim_sch;
struct afe_param_id_rt_proxy_port_cfg rtproxy;
struct afe_param_id_internal_bt_fm_cfg int_bt_fm;
+ struct afe_param_id_pseudo_port_cfg pseudo_port;
} __packed;
struct afe_audioif_config_command_no_payload {
diff --git a/sound/soc/msm/msm8974.c b/sound/soc/msm/msm8974.c
index f8185bb..cf1202e 100644
--- a/sound/soc/msm/msm8974.c
+++ b/sound/soc/msm/msm8974.c
@@ -1326,6 +1326,30 @@
.be_hw_params_fixup = msm_slim_0_tx_be_hw_params_fixup,
.ops = &msm8974_be_ops,
},
+ /* Incall Record Uplink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_TX,
+ .stream_name = "Voice Uplink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32772",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_TX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ },
+ /* Incall Record Downlink BACK END DAI Link */
+ {
+ .name = LPASS_BE_INCALL_RECORD_RX,
+ .stream_name = "Voice Downlink Capture",
+ .cpu_dai_name = "msm-dai-q6-dev.32771",
+ .platform_name = "msm-pcm-routing",
+ .codec_name = "msm-stub-codec.1",
+ .codec_dai_name = "msm-stub-tx",
+ .no_pcm = 1,
+ .be_id = MSM_BACKEND_DAI_INCALL_RECORD_RX,
+ .be_hw_params_fixup = msm_be_hw_params_fixup,
+ },
};
struct snd_soc_card snd_soc_card_msm8974 = {
diff --git a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
index a307bcc..6f0dbf2 100644
--- a/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-dai-q6-v2.c
@@ -432,12 +432,11 @@
if (!test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
switch (dai->id) {
case VOICE_PLAYBACK_TX:
- case VOICE_RECORD_TX:
- case VOICE_RECORD_RX:
rc = afe_start_pseudo_port(dai->id);
+ break;
default:
rc = afe_port_start(dai->id, &dai_data->port_config,
- dai_data->rate);
+ dai_data->rate);
}
if (IS_ERR_VALUE(rc))
@@ -606,6 +605,36 @@
return 0;
}
+static int msm_dai_q6_psuedo_port_hw_params(struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai, int stream)
+{
+ struct msm_dai_q6_dai_data *dai_data = dev_get_drvdata(dai->dev);
+
+ dai_data->channels = params_channels(params);
+ dai_data->rate = params_rate(params);
+
+ /* Q6 only supports 16 as now */
+ dai_data->port_config.pseudo_port.pseud_port_cfg_minor_version =
+ AFE_API_VERSION_PSEUDO_PORT_CONFIG;
+ dai_data->port_config.pseudo_port.num_channels =
+ params_channels(params);
+ dai_data->port_config.pseudo_port.bit_width = 16;
+ dai_data->port_config.pseudo_port.data_format = 0;
+ dai_data->port_config.pseudo_port.timing_mode =
+ AFE_PSEUDOPORT_TIMING_MODE_TIMER;
+ dai_data->port_config.pseudo_port.sample_rate = params_rate(params);
+
+ dev_dbg(dai->dev, "%s: bit_wd[%hu] num_channels [%hu] format[%hu]\n"
+ "timing Mode %hu sample_rate %d\n", __func__,
+ dai_data->port_config.pseudo_port.bit_width,
+ dai_data->port_config.pseudo_port.num_channels,
+ dai_data->port_config.pseudo_port.data_format,
+ dai_data->port_config.pseudo_port.timing_mode,
+ dai_data->port_config.pseudo_port.sample_rate);
+
+ return 0;
+}
+
/* Current implementation assumes hw_param is called once
* This may not be the case but what to do when ADM and AFE
* port are already opened and parameter changes
@@ -649,9 +678,12 @@
rc = msm_dai_q6_afe_rtproxy_hw_params(params, dai);
break;
case VOICE_PLAYBACK_TX:
+ rc = 0;
+ break;
case VOICE_RECORD_RX:
case VOICE_RECORD_TX:
- rc = 0;
+ rc = msm_dai_q6_psuedo_port_hw_params(params,
+ dai, substream->stream);
break;
default:
dev_err(dai->dev, "invalid AFE port ID\n");
@@ -671,8 +703,6 @@
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
switch (dai->id) {
case VOICE_PLAYBACK_TX:
- case VOICE_RECORD_TX:
- case VOICE_RECORD_RX:
pr_debug("%s, stop pseudo port:%d\n",
__func__, dai->id);
rc = afe_stop_pseudo_port(dai->id);
@@ -832,8 +862,6 @@
if (test_bit(STATUS_PORT_STARTED, dai_data->status_mask)) {
switch (dai->id) {
case VOICE_PLAYBACK_TX:
- case VOICE_RECORD_TX:
- case VOICE_RECORD_RX:
pr_debug("%s, stop pseudo port:%d\n",
__func__, dai->id);
rc = afe_stop_pseudo_port(dai->id);
@@ -969,6 +997,21 @@
.remove = msm_dai_q6_dai_remove,
};
+static struct snd_soc_dai_driver msm_dai_q6_incall_record_dai = {
+ .capture = {
+ .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 |
+ SNDRV_PCM_RATE_16000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .channels_min = 1,
+ .channels_max = 2,
+ .rate_min = 8000,
+ .rate_max = 48000,
+ },
+ .ops = &msm_dai_q6_ops,
+ .probe = msm_dai_q6_dai_probe,
+ .remove = msm_dai_q6_dai_remove,
+};
+
static int __devinit msm_auxpcm_dev_probe(struct platform_device *pdev)
{
int id;
@@ -1879,6 +1922,12 @@
case RT_PROXY_DAI_002_TX:
rc = snd_soc_register_dai(&pdev->dev, &msm_dai_q6_afe_tx_dai);
break;
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ rc = snd_soc_register_dai(&pdev->dev,
+ &msm_dai_q6_incall_record_dai);
+ break;
+
default:
rc = -ENODEV;
break;
diff --git a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
index 17c18dd..fbdbbf6 100644
--- a/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
+++ b/sound/soc/msm/qdsp6v2/msm-pcm-routing-v2.c
@@ -2059,6 +2059,8 @@
{"BE_OUT", NULL, "SLIMBUS_3_RX"},
{"BE_OUT", NULL, "AUX_PCM_RX"},
{"AUX_PCM_TX", NULL, "BE_IN"},
+ {"INCALL_RECORD_TX", NULL, "BE_IN"},
+ {"INCALL_RECORD_RX", NULL, "BE_IN"},
};
static int msm_pcm_routing_hw_params(struct snd_pcm_substream *substream,
diff --git a/sound/soc/msm/qdsp6v2/q6afe.c b/sound/soc/msm/qdsp6v2/q6afe.c
index fb6b56e..9387d21 100644
--- a/sound/soc/msm/qdsp6v2/q6afe.c
+++ b/sound/soc/msm/qdsp6v2/q6afe.c
@@ -227,6 +227,10 @@
case SLIMBUS_1_TX:
ret_size = SIZEOF_CFG_CMD(afe_param_id_slimbus_cfg);
break;
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ ret_size = SIZEOF_CFG_CMD(afe_param_id_pseudo_port_cfg);
+ break;
case RT_PROXY_PORT_001_RX:
case RT_PROXY_PORT_001_TX:
ret_size = SIZEOF_CFG_CMD(afe_param_id_rt_proxy_port_cfg);
@@ -410,6 +414,10 @@
case HDMI_RX:
cfg_type = AFE_PARAM_ID_HDMI_CONFIG;
break;
+ case VOICE_RECORD_RX:
+ case VOICE_RECORD_TX:
+ cfg_type = AFE_PARAM_ID_PSEUDO_PORT_CONFIG;
+ break;
case SLIMBUS_0_RX:
case SLIMBUS_0_TX:
case SLIMBUS_1_RX:
diff --git a/sound/soc/msm/qdsp6v2/q6voice.c b/sound/soc/msm/qdsp6v2/q6voice.c
index 263f47f..349fcf2 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.c
+++ b/sound/soc/msm/qdsp6v2/q6voice.c
@@ -2928,23 +2928,25 @@
cvs_start_record.hdr.src_port = v->session_id;
cvs_start_record.hdr.dest_port = cvs_handle;
cvs_start_record.hdr.token = 0;
- cvs_start_record.hdr.opcode = VSS_ISTREAM_CMD_START_RECORD;
+ cvs_start_record.hdr.opcode = VSS_IRECORD_CMD_START;
+ cvs_start_record.rec_mode.port_id =
+ VSS_IRECORD_PORT_ID_DEFAULT;
if (rec_mode == VOC_REC_UPLINK) {
cvs_start_record.rec_mode.rx_tap_point =
- VSS_TAP_POINT_NONE;
+ VSS_IRECORD_TAP_POINT_NONE;
cvs_start_record.rec_mode.tx_tap_point =
- VSS_TAP_POINT_STREAM_END;
+ VSS_IRECORD_TAP_POINT_STREAM_END;
} else if (rec_mode == VOC_REC_DOWNLINK) {
cvs_start_record.rec_mode.rx_tap_point =
- VSS_TAP_POINT_STREAM_END;
+ VSS_IRECORD_TAP_POINT_STREAM_END;
cvs_start_record.rec_mode.tx_tap_point =
- VSS_TAP_POINT_NONE;
+ VSS_IRECORD_TAP_POINT_NONE;
} else if (rec_mode == VOC_REC_BOTH) {
cvs_start_record.rec_mode.rx_tap_point =
- VSS_TAP_POINT_STREAM_END;
+ VSS_IRECORD_TAP_POINT_STREAM_END;
cvs_start_record.rec_mode.tx_tap_point =
- VSS_TAP_POINT_STREAM_END;
+ VSS_IRECORD_TAP_POINT_STREAM_END;
} else {
pr_err("%s: Invalid in-call rec_mode %d\n", __func__,
rec_mode);
@@ -3011,7 +3013,7 @@
cvs_stop_record.src_port = v->session_id;
cvs_stop_record.dest_port = cvs_handle;
cvs_stop_record.token = 0;
- cvs_stop_record.opcode = VSS_ISTREAM_CMD_STOP_RECORD;
+ cvs_stop_record.opcode = VSS_IRECORD_CMD_STOP;
v->cvs_state = CMD_STATUS_FAIL;
@@ -4166,8 +4168,8 @@
case VSS_ICOMMON_CMD_SET_UI_PROPERTY:
case VSS_ISTREAM_CMD_START_PLAYBACK:
case VSS_ISTREAM_CMD_STOP_PLAYBACK:
- case VSS_ISTREAM_CMD_START_RECORD:
- case VSS_ISTREAM_CMD_STOP_RECORD:
+ case VSS_IRECORD_CMD_START:
+ case VSS_IRECORD_CMD_STOP:
case VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE:
case VSS_ISTREAM_CMD_SET_OOB_PACKET_EXCHANGE_CONFIG:
pr_debug("%s: cmd = 0x%x\n", __func__, ptr[0]);
diff --git a/sound/soc/msm/qdsp6v2/q6voice.h b/sound/soc/msm/qdsp6v2/q6voice.h
index 6fb4b04..d19697a 100644
--- a/sound/soc/msm/qdsp6v2/q6voice.h
+++ b/sound/soc/msm/qdsp6v2/q6voice.h
@@ -495,17 +495,26 @@
#define VSS_ISTREAM_CMD_STOP_PLAYBACK 0x00011239
/* Stop the in-call music delivery on the Tx voice path. */
-#define VSS_ISTREAM_CMD_START_RECORD 0x00011236
+#define VSS_IRECORD_CMD_START 0x000112BE
/* Start in-call conversation recording. */
-#define VSS_ISTREAM_CMD_STOP_RECORD 0x00011237
+#define VSS_IRECORD_CMD_STOP 0x00011237
/* Stop in-call conversation recording. */
-#define VSS_TAP_POINT_NONE 0x00010F78
+#define VSS_IRECORD_PORT_ID_DEFAULT 0x0000FFFF
+/* Default AFE port ID. */
+
+#define VSS_IRECORD_TAP_POINT_NONE 0x00010F78
/* Indicates no tapping for specified path. */
-#define VSS_TAP_POINT_STREAM_END 0x00010F79
+#define VSS_IRECORD_TAP_POINT_STREAM_END 0x00010F79
/* Indicates that specified path should be tapped at the end of the stream. */
+#define VSS_IRECORD_MODE_TX_RX_STEREO 0x00010F7A
+/* Select Tx on left channel and Rx on right channel. */
+
+#define VSS_IRECORD_MODE_TX_RX_MIXING 0x00010F7B
+/* Select mixed Tx and Rx paths. */
+
#define VSS_ISTREAM_EVT_NOT_READY 0x000110FD
#define VSS_ISTREAM_EVT_READY 0x000110FC
@@ -529,16 +538,30 @@
#define VSS_ISTREAM_CMD_SET_PACKET_EXCHANGE_MODE 0x0001136A
-struct vss_istream_cmd_start_record_t {
+struct vss_irecord_cmd_start_t {
uint32_t rx_tap_point;
/* Tap point to use on the Rx path. Supported values are:
- * VSS_TAP_POINT_NONE : Do not record Rx path.
- * VSS_TAP_POINT_STREAM_END : Rx tap point is at the end of the stream.
+ * VSS_IRECORD_TAP_POINT_NONE : Do not record Rx path.
+ * VSS_IRECORD_TAP_POINT_STREAM_END : Rx tap point is at the end of
+ * the stream.
*/
uint32_t tx_tap_point;
/* Tap point to use on the Tx path. Supported values are:
- * VSS_TAP_POINT_NONE : Do not record tx path.
- * VSS_TAP_POINT_STREAM_END : Tx tap point is at the end of the stream.
+ * VSS_IRECORD_TAP_POINT_NONE : Do not record tx path.
+ * VSS_IRECORD_TAP_POINT_STREAM_END : Tx tap point is at the end of
+ * the stream.
+ */
+ uint16_t port_id;
+ /* AFE Port ID to whcih the conversation recording stream needs to be
+ * sent. Set this to #VSS_IRECORD_PORT_ID_DEFAULT to use default AFE
+ * pseudo ports (0x8003 for Rx and 0x8004 for Tx).
+ */
+ uint32_t mode;
+ /* Recording Mode. The mode parameter value is ignored if the port_id
+ * is set to #VSS_IRECORD_PORT_ID_DEFAULT.
+ * The supported values:
+ * #VSS_IRECORD_MODE_TX_RX_STEREO
+ * #VSS_IRECORD_MODE_TX_RX_MIXING
*/
} __packed;
@@ -782,7 +805,7 @@
} __packed;
struct cvs_start_record_cmd {
struct apr_hdr hdr;
- struct vss_istream_cmd_start_record_t rec_mode;
+ struct vss_irecord_cmd_start_t rec_mode;
} __packed;
struct cvs_dec_buffer_ready_cmd {