clear-pkgs-linux-iot-lts2018/0341-ASoC-Intel-Multiple-I-...

204 lines
6.3 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: "S, Pavan K" <pavan.k.s@intel.com>
Date: Fri, 30 Jun 2017 20:52:37 +0530
Subject: [PATCH] ASoC: Intel: Multiple I/O PCM format support for pipe
If a pipe supports multiple input/output formats, kcontrol is
created and selection of pipe input and output configuration
is done based on control set.
If more than one configuration is supported, then this patch
allows user to select configuration of choice
using amixer settings.
Change-Id: Ie977d9857507a13aade10a1175994ecabcceed0c
Signed-off-by: S, Pavan K <pavan.k.s@intel.com>
Reviewed-on:
Reviewed-by: R, Dharageswari <dharageswari.r@intel.com>
Reviewed-by: Prodduvaka, Leoni
Reviewed-by: Prusty, Subhransu S <subhransu.s.prusty@intel.com>
Reviewed-by: Singh, Guneshwor O <guneshwor.o.singh@intel.com>
Reviewed-by: Diwakar, Praveen <praveen.diwakar@intel.com>
Tested-by: Sm, Bhadur A <bhadur.a.sm@intel.com>
---
include/uapi/sound/skl-tplg-interface.h | 1 +
sound/soc/intel/skylake/skl-topology.c | 103 ++++++++++++++++++++++++
sound/soc/intel/skylake/skl-topology.h | 1 +
3 files changed, 105 insertions(+)
diff --git a/include/uapi/sound/skl-tplg-interface.h b/include/uapi/sound/skl-tplg-interface.h
index 2dceadfbc1f5..89844fb10aa5 100644
--- a/include/uapi/sound/skl-tplg-interface.h
+++ b/include/uapi/sound/skl-tplg-interface.h
@@ -19,6 +19,7 @@
#define SKL_CONTROL_TYPE_BYTE_TLV 0x100
#define SKL_CONTROL_TYPE_MIC_SELECT 0x102
#define SKL_CONTROL_TYPE_BYTE_PROBE 0x101
+#define SKL_CONTROL_TYPE_MULTI_IO_SELECT 0x103
#define HDA_SST_CFG_MAX 900 /* size of copier cfg*/
#define MAX_IN_QUEUE 8
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c
index 4343f99689fa..5f51debc4638 100644
--- a/sound/soc/intel/skylake/skl-topology.c
+++ b/sound/soc/intel/skylake/skl-topology.c
@@ -60,6 +60,14 @@ static const int mic_quatro_list[][SKL_CH_QUATRO] = {
#define CHECK_HW_PARAMS(ch, freq, bps, prm_ch, prm_freq, prm_bps) \
((ch == prm_ch) && (bps == prm_bps) && (freq == prm_freq))
+#define GET_PIPE(ppl, skl, node, pipe_id, pipe) \
+ do { list_for_each_entry(ppl, &skl->ppl_list, node) { \
+ if (ppl->pipe->ppl_id == pipe_id) { \
+ pipe = ppl->pipe; \
+ break; } \
+ } \
+ } while (0)
+
static void skl_init_single_module_pipe(struct snd_soc_dapm_widget *w,
struct skl *skl);
@@ -895,6 +903,35 @@ static int skl_tplg_unload_pipe_modules(struct skl_sst *ctx,
return ret;
}
+static bool is_skl_tplg_multi_fmt(struct skl *skl, struct skl_pipe *pipe)
+{
+ int i;
+ struct skl_pipe_fmt *cur_fmt;
+ struct skl_pipe_fmt *next_fmt;
+
+ if (pipe->conn_type == SKL_PIPE_CONN_TYPE_FE &&
+ pipe->nr_cfgs > 1) {
+ for (i = 0; i < pipe->nr_cfgs-1; i++) {
+ if (pipe->direction == SNDRV_PCM_STREAM_PLAYBACK) {
+ cur_fmt = &pipe->configs[i].out_fmt;
+ next_fmt = &pipe->configs[i+1].out_fmt;
+ } else {
+ cur_fmt = &pipe->configs[i].in_fmt;
+ next_fmt = &pipe->configs[i+1].in_fmt;
+ }
+ if (!CHECK_HW_PARAMS(cur_fmt->channels, cur_fmt->freq,
+ cur_fmt->bps,
+ next_fmt->channels,
+ next_fmt->freq, next_fmt->bps))
+ return true;
+ }
+ } else if (pipe->nr_cfgs > 1) {
+ return true;
+ }
+
+ return false;
+}
+
/*
* Here, we select pipe format based on the pipe type and pipe
* direction to determine the current config index for the pipeline.
@@ -912,12 +949,21 @@ skl_tplg_get_pipe_config(struct skl *skl, struct skl_module_cfg *mconfig)
struct skl_pipe_fmt *fmt = NULL;
bool in_fmt = false;
int i;
+ bool ret;
if (pipe->nr_cfgs == 0) {
pipe->cur_config_idx = 0;
return 0;
}
+ ret = is_skl_tplg_multi_fmt(skl, pipe);
+ if (ret) {
+ pipe->cur_config_idx = pipe->pipe_config_idx;
+ pipe->memory_pages = pconfig->mem_pages;
+ dev_dbg(ctx->dev, "found pipe config idx:%d\n",
+ pipe->cur_config_idx);
+ return 0;
+ }
if (pipe->conn_type == SKL_PIPE_CONN_TYPE_NONE) {
dev_dbg(ctx->dev, "No conn_type detected, take 0th config\n");
pipe->cur_config_idx = 0;
@@ -1778,6 +1824,58 @@ int skl_tplg_dsp_log_set(struct snd_kcontrol *kcontrol,
return 0;
}
+static int skl_tplg_multi_config_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(component);
+ struct skl *skl = ebus_to_skl(ebus);
+ struct skl_pipeline *ppl;
+ struct skl_pipe *pipe = NULL;
+ u32 *pipe_id;
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+
+ if (!ec)
+ return -EINVAL;
+
+ pipe_id = ec->dobj.private;
+ GET_PIPE(ppl, skl, node, *pipe_id, pipe);
+ if (!pipe)
+ return -EIO;
+
+ ucontrol->value.enumerated.item[0] = pipe->pipe_config_idx;
+
+ return 0;
+}
+
+static int skl_tplg_multi_config_set(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
+ struct hdac_ext_bus *ebus = snd_soc_component_get_drvdata(component);
+ struct skl *skl = ebus_to_skl(ebus);
+ struct skl_pipeline *ppl;
+ struct skl_pipe *pipe = NULL;
+ struct soc_enum *ec = (struct soc_enum *)kcontrol->private_value;
+ u32 *pipe_id;
+
+ if (!ec)
+ return -EINVAL;
+
+ if (ucontrol->value.enumerated.item[0] > ec->items)
+ return -EINVAL;
+
+ pipe_id = ec->dobj.private;
+ GET_PIPE(ppl, skl, node, *pipe_id, pipe);
+ if (!pipe)
+ return -EIO;
+
+ pipe->pipe_config_idx = ucontrol->value.enumerated.item[0];
+
+ return 0;
+}
+
+
static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol,
unsigned int __user *data, unsigned int size)
{
@@ -2571,6 +2669,11 @@ static const struct snd_soc_tplg_kcontrol_ops skl_tplg_kcontrol_ops[] = {
.get = skl_tplg_mic_control_get,
.put = skl_tplg_mic_control_set,
},
+ {
+ .id = SKL_CONTROL_TYPE_MULTI_IO_SELECT,
+ .get = skl_tplg_multi_config_get,
+ .put = skl_tplg_multi_config_set,
+ },
};
static int skl_tplg_fill_pipe_cfg(struct device *dev,
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h
index 02256d70f60f..07d041fc8b72 100644
--- a/sound/soc/intel/skylake/skl-topology.h
+++ b/sound/soc/intel/skylake/skl-topology.h
@@ -342,6 +342,7 @@ struct skl_pipe {
struct skl_path_config configs[SKL_MAX_PATH_CONFIGS];
struct list_head w_list;
bool passthru;
+ u32 pipe_config_idx;
};
enum skl_module_state {
--
https://clearlinux.org