ASoC: SOF: Add asynchronous sample rate converter topology support
authorSeppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Tue, 10 Dec 2019 00:48:47 +0000 (18:48 -0600)
committerMark Brown <broonie@kernel.org>
Tue, 10 Dec 2019 13:13:11 +0000 (13:13 +0000)
This patch adds into SOF topology the handling of ASRC DAPM type,
adds the tokens to configure the ASRC, and implement component IPC
into the driver.

Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20191210004854.16845-2-pierre-louis.bossart@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sof/topology.h
include/uapi/sound/sof/abi.h
include/uapi/sound/sof/tokens.h
sound/soc/sof/topology.c

index c47b3624092030992e3e7dc071d5c822eff3566d..8e76178fedf08a0adf47d95f612672dd1fa6ef3b 100644 (file)
@@ -36,6 +36,7 @@ enum sof_comp_type {
        SOF_COMP_KPB,                   /* A key phrase buffer component */
        SOF_COMP_SELECTOR,              /**< channel selector component */
        SOF_COMP_DEMUX,
+       SOF_COMP_ASRC,          /**< Asynchronous sample rate converter */
        /* keep FILEREAD/FILEWRITE as the last ones */
        SOF_COMP_FILEREAD = 10000,      /**< host test based file IO */
        SOF_COMP_FILEWRITE = 10001,     /**< host test based file IO */
@@ -147,6 +148,32 @@ struct sof_ipc_comp_src {
        uint32_t rate_mask;     /**< SOF_RATE_ supported rates */
 } __packed;
 
+/* generic ASRC component */
+struct sof_ipc_comp_asrc {
+       struct sof_ipc_comp comp;
+       struct sof_ipc_comp_config config;
+       /* either source or sink rate must be non zero */
+       uint32_t source_rate;           /**< Define fixed source rate or */
+                                       /**< use 0 to indicate need to get */
+                                       /**< the rate from stream */
+       uint32_t sink_rate;             /**< Define fixed sink rate or */
+                                       /**< use 0 to indicate need to get */
+                                       /**< the rate from stream */
+       uint32_t asynchronous_mode;     /**< synchronous 0, asynchronous 1 */
+                                       /**< When 1 the ASRC tracks and */
+                                       /**< compensates for drift. */
+       uint32_t operation_mode;        /**< push 0, pull 1, In push mode the */
+                                       /**< ASRC consumes a defined number */
+                                       /**< of frames at input, with varying */
+                                       /**< number of frames at output. */
+                                       /**< In pull mode the ASRC outputs */
+                                       /**< a defined number of frames while */
+                                       /**< number of input frames varies. */
+
+       /* reserved for future use */
+       uint32_t reserved[4];
+} __attribute__((packed));
+
 /* generic MUX component */
 struct sof_ipc_comp_mux {
        struct sof_ipc_comp comp;
index ebfdc20ca081852933d8639e8c2d51203e40d48e..c0ef1643c7538938204b497f14f7e9b8ee7aff65 100644 (file)
@@ -26,7 +26,7 @@
 
 /* SOF ABI version major, minor and patch numbers */
 #define SOF_ABI_MAJOR 3
-#define SOF_ABI_MINOR 11
+#define SOF_ABI_MINOR 12
 #define SOF_ABI_PATCH 0
 
 /* SOF ABI version number. Format within 32bit word is MMmmmppp */
index 76883e6fb75081712f520d88a7b2324d80349979..a9a5c4d0a89202e5bc9aea188649293937189ac3 100644 (file)
 #define SOF_TKN_SRC_RATE_IN                    300
 #define SOF_TKN_SRC_RATE_OUT                   301
 
+/* ASRC */
+#define SOF_TKN_ASRC_RATE_IN                   320
+#define SOF_TKN_ASRC_RATE_OUT                  321
+#define SOF_TKN_ASRC_ASYNCHRONOUS_MODE         322
+#define SOF_TKN_ASRC_OPERATION_MODE            323
+
 /* PCM */
 #define SOF_TKN_PCM_DMAC_CONFIG                        353
 
index 1ae06a1f9b0bbebae6b1301863783271a106a868..215f4d23ddfe2a3ee601d57ab17185079e35d360 100644 (file)
@@ -573,6 +573,20 @@ static const struct sof_topology_token src_tokens[] = {
                offsetof(struct sof_ipc_comp_src, sink_rate), 0},
 };
 
+/* ASRC */
+static const struct sof_topology_token asrc_tokens[] = {
+       {SOF_TKN_ASRC_RATE_IN, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc_comp_asrc, source_rate), 0},
+       {SOF_TKN_ASRC_RATE_OUT, SND_SOC_TPLG_TUPLE_TYPE_WORD, get_token_u32,
+               offsetof(struct sof_ipc_comp_asrc, sink_rate), 0},
+       {SOF_TKN_ASRC_ASYNCHRONOUS_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+               get_token_u32,
+               offsetof(struct sof_ipc_comp_asrc, asynchronous_mode), 0},
+       {SOF_TKN_ASRC_OPERATION_MODE, SND_SOC_TPLG_TUPLE_TYPE_WORD,
+               get_token_u32,
+               offsetof(struct sof_ipc_comp_asrc, operation_mode), 0},
+};
+
 /* Tone */
 static const struct sof_topology_token tone_tokens[] = {
 };
@@ -1782,6 +1796,67 @@ err:
        return ret;
 }
 
+/*
+ * ASRC Topology
+ */
+
+static int sof_widget_load_asrc(struct snd_soc_component *scomp, int index,
+                               struct snd_sof_widget *swidget,
+                               struct snd_soc_tplg_dapm_widget *tw,
+                               struct sof_ipc_comp_reply *r)
+{
+       struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp);
+       struct snd_soc_tplg_private *private = &tw->priv;
+       struct sof_ipc_comp_asrc *asrc;
+       int ret;
+
+       asrc = kzalloc(sizeof(*asrc), GFP_KERNEL);
+       if (!asrc)
+               return -ENOMEM;
+
+       /* configure ASRC IPC message */
+       asrc->comp.hdr.size = sizeof(*asrc);
+       asrc->comp.hdr.cmd = SOF_IPC_GLB_TPLG_MSG | SOF_IPC_TPLG_COMP_NEW;
+       asrc->comp.id = swidget->comp_id;
+       asrc->comp.type = SOF_COMP_ASRC;
+       asrc->comp.pipeline_id = index;
+       asrc->config.hdr.size = sizeof(asrc->config);
+
+       ret = sof_parse_tokens(scomp, asrc, asrc_tokens,
+                              ARRAY_SIZE(asrc_tokens), private->array,
+                              le32_to_cpu(private->size));
+       if (ret != 0) {
+               dev_err(scomp->dev, "error: parse asrc tokens failed %d\n",
+                       private->size);
+               goto err;
+       }
+
+       ret = sof_parse_tokens(scomp, &asrc->config, comp_tokens,
+                              ARRAY_SIZE(comp_tokens), private->array,
+                              le32_to_cpu(private->size));
+       if (ret != 0) {
+               dev_err(scomp->dev, "error: parse asrc.cfg tokens failed %d\n",
+                       le32_to_cpu(private->size));
+               goto err;
+       }
+
+       dev_dbg(scomp->dev, "asrc %s: source rate %d sink rate %d "
+               "asynch %d operation %d\n",
+               swidget->widget->name, asrc->source_rate, asrc->sink_rate,
+               asrc->asynchronous_mode, asrc->operation_mode);
+       sof_dbg_comp_config(scomp, &asrc->config);
+
+       swidget->private = asrc;
+
+       ret = sof_ipc_tx_message(sdev->ipc, asrc->comp.hdr.cmd, asrc,
+                                sizeof(*asrc), r, sizeof(*r));
+       if (ret >= 0)
+               return ret;
+err:
+       kfree(asrc);
+       return ret;
+}
+
 /*
  * Signal Generator Topology
  */
@@ -2195,6 +2270,9 @@ static int sof_widget_ready(struct snd_soc_component *scomp, int index,
        case snd_soc_dapm_src:
                ret = sof_widget_load_src(scomp, index, swidget, tw, &reply);
                break;
+       case snd_soc_dapm_asrc:
+               ret = sof_widget_load_asrc(scomp, index, swidget, tw, &reply);
+               break;
        case snd_soc_dapm_siggen:
                ret = sof_widget_load_siggen(scomp, index, swidget, tw, &reply);
                break;