From patchwork Mon May 9 08:58:10 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Cezary Rojewski X-Patchwork-Id: 571023 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 57492C433EF for ; Mon, 9 May 2022 08:54:12 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 6A84C1921; Mon, 9 May 2022 10:53:20 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 6A84C1921 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1652086450; bh=v9Oy3M6qVpi9RQ+ICLK4FNOi8eIZA530mpjwNEP1pZY=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=H074Y2w5e1ZrolS+gmwRStkQXHCTZ50hcho1HNvNU9K3kdfOa1W69omOKfR2RlKZU Wvh8xDPtbIPbR14x5U3SrfruErruRD3YlSDuFfGG0U46BkHpgzKwfTs/6CIjAMu8iE 7Bqwbcp5km6qaJDu2nTqw0Y/Ug8mfflM1S05yOcs= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id CFCF5F804A9; Mon, 9 May 2022 10:49:48 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5FA91F805B6; Mon, 9 May 2022 10:49:47 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 4476BF80269 for ; Mon, 9 May 2022 10:48:48 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 4476BF80269 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="njcGHG6v" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1652086129; x=1683622129; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=v9Oy3M6qVpi9RQ+ICLK4FNOi8eIZA530mpjwNEP1pZY=; b=njcGHG6vBWPfe6Z2KgszCr2NkSzuLBqdlfL64wZ9cJUfklj3nkyxkEPP x6HZ/tKyo1DGHXgIDNCbW4BKGNAKt/v+5q2I2tBasaqzpTqHwteIEyBcD aJI4V3KAIbfNoaxvMpgUqJqqtS0QJWZPQbmV9D3KmUHJczXMSnEOcFagn YZMw0SCQEAz8pG8FTUUpjuqFEoMli6yaWngQF70YXQKspljklCrGo1QuF U3dyRit5XEns1r1tRPzTJuMIqn4LXaCgCJCuQFpd/aa/tSLF3VTpzRrOd RzAJiUg91lsOYjpalxl5TLEGk3aLyeU81LIsn/mIvpcPdGzxaUVm7tHu6 Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10341"; a="294208527" X-IronPort-AV: E=Sophos;i="5.91,210,1647327600"; d="scan'208";a="294208527" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 May 2022 01:48:46 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.91,210,1647327600"; d="scan'208";a="738068247" Received: from crojewsk-ctrl.igk.intel.com ([10.102.9.28]) by orsmga005.jf.intel.com with ESMTP; 09 May 2022 01:48:43 -0700 From: Cezary Rojewski To: alsa-devel@alsa-project.org, broonie@kernel.org Subject: [PATCH v2 04/15] ASoC: Intel: avs: non-HDA PCM BE operations Date: Mon, 9 May 2022 10:58:10 +0200 Message-Id: <20220509085821.3852259-5-cezary.rojewski@intel.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220509085821.3852259-1-cezary.rojewski@intel.com> References: <20220509085821.3852259-1-cezary.rojewski@intel.com> MIME-Version: 1.0 Cc: Cezary Rojewski , upstream@semihalf.com, harshapriya.n@intel.com, rad@semihalf.com, pierre-louis.bossart@linux.intel.com, tiwai@suse.com, hdegoede@redhat.com, amadeuszx.slawinski@linux.intel.com, cujomalainey@chromium.org, lma@semihalf.com X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" DMIC and I2S interfaces differ in DMA operations from the HDAudio interface. With that in mind, implement all DAI operations to handle non-HDA BE interfaces. To prevent code duplication in newly added code, I2S platform registering is dynamic - makes use of specified port_mask and TDMs array to populate as many DAIs as required. Signed-off-by: Amadeusz Sławiński Signed-off-by: Cezary Rojewski --- sound/soc/intel/avs/avs.h | 4 + sound/soc/intel/avs/pcm.c | 222 +++++++++++++++++++++++++++++++++++++- 2 files changed, 225 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index 14b4a780a91c..b4fd67fac17d 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -270,4 +270,8 @@ struct avs_soc_component { extern const struct snd_soc_dai_ops avs_dai_fe_ops; +int avs_dmic_platform_register(struct avs_dev *adev, const char *name); +int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms); + #endif /* __SOUND_SOC_INTEL_AVS_H */ diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 9d01ed37c11e..079fa19f7d7b 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -112,6 +112,23 @@ static int avs_dai_hw_params(struct snd_pcm_substream *substream, return 0; } +static int avs_dai_be_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *be_hw_params, struct snd_soc_dai *dai, + int dma_id) +{ + struct snd_pcm_hw_params *fe_hw_params = NULL; + struct snd_soc_pcm_runtime *fe, *be; + struct snd_soc_dpcm *dpcm; + + be = asoc_substream_to_rtd(substream); + for_each_dpcm_fe(be, substream->stream, dpcm) { + fe = dpcm->fe; + fe_hw_params = &fe->dpcm[substream->stream].hw_params; + } + + return avs_dai_hw_params(substream, fe_hw_params, be_hw_params, dai, dma_id); +} + static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -134,6 +151,100 @@ static int avs_dai_prepare(struct avs_dev *adev, struct snd_pcm_substream *subst return ret; } +static int avs_dai_nonhda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + return avs_dai_startup(substream, dai, false); +} + +static void avs_dai_nonhda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dma_data *data; + + data = snd_soc_dai_get_dma_data(dai, substream); + + snd_soc_dai_set_dma_data(dai, substream, NULL); + kfree(data); +} + +static int avs_dai_nonhda_be_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) +{ + struct avs_dma_data *data; + + data = snd_soc_dai_get_dma_data(dai, substream); + if (data->path) + return 0; + + /* Actual port-id comes from topology. */ + return avs_dai_be_hw_params(substream, hw_params, dai, 0); +} + +static int avs_dai_nonhda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dma_data *data; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + data = snd_soc_dai_get_dma_data(dai, substream); + if (data->path) { + avs_path_free(data->path); + data->path = NULL; + } + + return 0; +} + +static int avs_dai_nonhda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + return avs_dai_prepare(to_avs_dev(dai->dev), substream, dai); +} + +static int avs_dai_nonhda_be_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct avs_dma_data *data; + int ret = 0; + + data = snd_soc_dai_get_dma_data(dai, substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + ret = avs_path_run(data->path, AVS_TPLG_TRIGGER_AUTO); + if (ret < 0) + dev_err(dai->dev, "run BE path failed: %d\n", ret); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + ret = avs_path_pause(data->path); + if (ret < 0) + dev_err(dai->dev, "pause BE path failed: %d\n", ret); + + if (cmd == SNDRV_PCM_TRIGGER_STOP) { + ret = avs_path_reset(data->path); + if (ret < 0) + dev_err(dai->dev, "reset BE path failed: %d\n", ret); + } + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = { + .startup = avs_dai_nonhda_be_startup, + .shutdown = avs_dai_nonhda_be_shutdown, + .hw_params = avs_dai_nonhda_be_hw_params, + .hw_free = avs_dai_nonhda_be_hw_free, + .prepare = avs_dai_nonhda_be_prepare, + .trigger = avs_dai_nonhda_be_trigger, +}; + static const unsigned int rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, @@ -589,7 +700,6 @@ static const struct snd_soc_component_driver avs_component_driver = { .non_legacy_dai_naming = true, }; -__maybe_unused static int avs_soc_component_register(struct device *dev, const char *name, const struct snd_soc_component_driver *drv, struct snd_soc_dai_driver *cpu_dais, int num_cpu_dais) @@ -611,3 +721,113 @@ static int avs_soc_component_register(struct device *dev, const char *name, return snd_soc_add_component(&acomp->base, cpu_dais, num_cpu_dais); } + +static struct snd_soc_dai_driver dmic_cpu_dais[] = { +{ + .name = "DMIC Pin", + .ops = &avs_dai_nonhda_be_ops, + .capture = { + .stream_name = "DMIC Rx", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "DMIC WoV Pin", + .ops = &avs_dai_nonhda_be_ops, + .capture = { + .stream_name = "DMIC WoV Rx", + .channels_min = 1, + .channels_max = 4, + .rates = SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +}; + +int avs_dmic_platform_register(struct avs_dev *adev, const char *name) +{ + return avs_soc_component_register(adev->dev, name, &avs_component_driver, dmic_cpu_dais, + ARRAY_SIZE(dmic_cpu_dais)); +} + +static const struct snd_soc_dai_driver i2s_dai_template = { + .ops = &avs_dai_nonhda_be_ops, + .playback = { + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .capture = { + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000 | + SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, +}; + +int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned long port_mask, + unsigned long *tdms) +{ + struct snd_soc_dai_driver *cpus, *dai; + size_t ssp_count, cpu_count; + int i, j; + + ssp_count = adev->hw_cfg.i2s_caps.ctrl_count; + cpu_count = hweight_long(port_mask); + if (tdms) + for_each_set_bit(i, &port_mask, ssp_count) + cpu_count += hweight_long(tdms[i]); + + cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL); + if (!cpus) + return -ENOMEM; + + dai = cpus; + for_each_set_bit(i, &port_mask, ssp_count) { + memcpy(dai, &i2s_dai_template, sizeof(*dai)); + + dai->name = + devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d Pin", i); + dai->playback.stream_name = + devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Tx", i); + dai->capture.stream_name = + devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d Rx", i); + + if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) + return -ENOMEM; + dai++; + } + + if (!tdms) + goto plat_register; + + for_each_set_bit(i, &port_mask, ssp_count) { + for_each_set_bit(j, &tdms[i], ssp_count) { + memcpy(dai, &i2s_dai_template, sizeof(*dai)); + + dai->name = + devm_kasprintf(adev->dev, GFP_KERNEL, "SSP%d:%d Pin", i, j); + dai->playback.stream_name = + devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Tx", i, j); + dai->capture.stream_name = + devm_kasprintf(adev->dev, GFP_KERNEL, "ssp%d:%d Rx", i, j); + + if (!dai->name || !dai->playback.stream_name || !dai->capture.stream_name) + return -ENOMEM; + dai++; + } + } + +plat_register: + return avs_soc_component_register(adev->dev, name, &avs_component_driver, cpus, cpu_count); +}