From patchwork Thu Jun 20 08:42:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Herve Codina X-Patchwork-Id: 13704993 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 bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (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 1F3FFC2BA1A for ; Thu, 20 Jun 2024 08:43:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:Cc:To:From: Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=EFI+0E0euoS+1MCJ9IhOD3qEiKcvASTCp8dMcDFqcOg=; b=3zu6EYkywxypVQ9ximn40JYX+t pCaFAxkk9dY0SnsZxAP0F+qkiOd1jg9mqmDhcAOAJEbFlJB3OEvw5jcaV82cEwfLN869MttkgUxSY 4ReInB1WR+bJjhffCAoqgpqmW52wCENug6+becKzlbX7/icjmzWWyhv4d4H3Q28kxbd3vhwkfq4vA CeVAM+koLAPJKhvMFRbFjq3ZJAh6T5tN+0PWO+5TPrD8Q7uA2ehcnWxYTY8iK53KO9Zq8cVxdubb0 0DKnK/lNek5iEaiKAMzrMX0Is6vHlNDBe65lOZ1OtOn8jQ4KheJdePgMuiW/d8AIRspMv87C86U15 Dc9vJwTw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1sKDO6-00000004CyU-0a0W; Thu, 20 Jun 2024 08:43:22 +0000 Received: from relay7-d.mail.gandi.net ([217.70.183.200]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1sKDO0-00000004CuD-0hzv for linux-arm-kernel@lists.infradead.org; Thu, 20 Jun 2024 08:43:19 +0000 Received: by mail.gandi.net (Postfix) with ESMTPA id D358620011; Thu, 20 Jun 2024 08:43:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=bootlin.com; s=gm1; t=1718872994; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=EFI+0E0euoS+1MCJ9IhOD3qEiKcvASTCp8dMcDFqcOg=; b=e9ggyz3+6HHiSIpE/iQE79+VB+G+1HKI0ClqW79MRrOOy8T7fXlAMKw4WIXXKungvubb4f U4bQHzxdmr2RKQEFz7Ov7VRzFfEwisFMTpCTGNProk/T0XFUTxjNZCdMxvPAziN9d1nIrx AQ8LWvEtHlG6sX5m0Lgl5XAdkY1B75R3ePcdks7wQWyGgQvV61TcANwNfHhFLkHaGPWYD3 VvUVP6D/eMJ0FUCS9UTI5fhfUrlJLSCsiLsMRVeRGnrqcgk70lTKCqjEey9n1RNyJcrTji PGroAx7J9W8cJSGP+WiJ7byUQ3mgfEY8T3KT/M01rmvh9DatmlZG4FDwFnkV6w== From: Herve Codina To: Herve Codina , Liam Girdwood , Mark Brown , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Qiang Zhao , Shengjiu Wang , Xiubo Li , Fabio Estevam , Nicolin Chen , Jaroslav Kysela , Takashi Iwai , Christophe Leroy Cc: alsa-devel@alsa-project.org, linuxppc-dev@lists.ozlabs.org, linux-sound@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Thomas Petazzoni Subject: [PATCH 04/10] ASoC: fsl: fsl_qmc_audio: Identify the QMC channel involved in completion routines Date: Thu, 20 Jun 2024 10:42:51 +0200 Message-ID: <20240620084300.397853-5-herve.codina@bootlin.com> X-Mailer: git-send-email 2.45.0 In-Reply-To: <20240620084300.397853-1-herve.codina@bootlin.com> References: <20240620084300.397853-1-herve.codina@bootlin.com> MIME-Version: 1.0 X-GND-Sasl: herve.codina@bootlin.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240620_014316_502139_D73144BB X-CRM114-Status: GOOD ( 18.98 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org The current QMC audio driver uses only one QMC channel per DAI. The context used by QMC channel transfer (read and write) completion routines does not contains any QMC channel and the only one available per DAI is used to schedule the next transfer. This works pretty well with only one QMC channel per DAI. The future support for non-inlerleave mode will use several QMC channel per DAI. In that case, QMC channel transfer completion routines need to identify the QMC channel related to the completion. In order to fill this lack, even if identifying the current QMC channel among several QMC channels is not needed for the current code, add one indirection level and introduce the qmc_dai_chan data structrure. This structure contains the QMC channel involved in the completion and refererences to the runtime context (capture and playback) used by the DAI. Signed-off-by: Herve Codina --- sound/soc/fsl/fsl_qmc_audio.c | 72 +++++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index e8281e548746..b07770257bad 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -17,13 +17,19 @@ #include #include +struct qmc_dai_chan { + struct qmc_dai_prtd *prtd_tx; + struct qmc_dai_prtd *prtd_rx; + struct qmc_chan *qmc_chan; +}; + struct qmc_dai { char *name; int id; struct device *dev; - struct qmc_chan *qmc_chan; unsigned int nb_tx_ts; unsigned int nb_rx_ts; + struct qmc_dai_chan chan; }; struct qmc_audio { @@ -86,9 +92,12 @@ static int qmc_audio_pcm_hw_params(struct snd_soc_component *component, static void qmc_audio_pcm_write_complete(void *context) { - struct qmc_dai_prtd *prtd = context; + struct qmc_dai_chan *chan = context; + struct qmc_dai_prtd *prtd; int ret; + prtd = chan->prtd_tx; + prtd->buffer_ended += prtd->period_size; if (prtd->buffer_ended >= prtd->buffer_size) prtd->buffer_ended = 0; @@ -97,9 +106,10 @@ static void qmc_audio_pcm_write_complete(void *context) if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, prtd); + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(prtd->qmc_dai->dev, "write_submit failed %d\n", ret); @@ -110,9 +120,12 @@ static void qmc_audio_pcm_write_complete(void *context) static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned int flags) { - struct qmc_dai_prtd *prtd = context; + struct qmc_dai_chan *chan = context; + struct qmc_dai_prtd *prtd; int ret; + prtd = chan->prtd_rx; + if (length != prtd->ch_dma_size) { dev_err(prtd->qmc_dai->dev, "read complete length = %zu, exp %zu\n", length, prtd->ch_dma_size); @@ -126,9 +139,10 @@ static void qmc_audio_pcm_read_complete(void *context, size_t length, unsigned i if (prtd->ch_dma_addr_current >= prtd->ch_dma_addr_end) prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, prtd); + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(prtd->qmc_dai->dev, "read_submit failed %d\n", ret); @@ -151,10 +165,13 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + prtd->qmc_dai->chan.prtd_tx = prtd; + /* Submit first chunk ... */ - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, prtd); + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -167,19 +184,23 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ - ret = qmc_chan_write_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_write_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_write_complete, prtd); + qmc_audio_pcm_write_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); return ret; } } else { + prtd->qmc_dai->chan.prtd_rx = prtd; + /* Submit first chunk ... */ - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, prtd); + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "read_submit failed %d\n", ret); @@ -192,9 +213,10 @@ static int qmc_audio_pcm_trigger(struct snd_soc_component *component, prtd->ch_dma_addr_current = prtd->ch_dma_addr_start; /* ... and send it */ - ret = qmc_chan_read_submit(prtd->qmc_dai->qmc_chan, + ret = qmc_chan_read_submit(prtd->qmc_dai->chan.qmc_chan, prtd->ch_dma_addr_current, prtd->ch_dma_size, - qmc_audio_pcm_read_complete, prtd); + qmc_audio_pcm_read_complete, + &prtd->qmc_dai->chan); if (ret) { dev_err(component->dev, "write_submit failed %d\n", ret); @@ -489,7 +511,7 @@ static int qmc_dai_hw_params(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { chan_param.mode = QMC_TRANSPARENT; chan_param.transp.max_rx_buf_size = params_period_bytes(params); - ret = qmc_chan_set_param(qmc_dai->qmc_chan, &chan_param); + ret = qmc_chan_set_param(qmc_dai->chan.qmc_chan, &chan_param); if (ret) { dev_err(dai->dev, "set param failed %d\n", ret); @@ -520,23 +542,23 @@ static int qmc_dai_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - ret = qmc_chan_start(qmc_dai->qmc_chan, direction); + ret = qmc_chan_start(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; break; case SNDRV_PCM_TRIGGER_STOP: - ret = qmc_chan_stop(qmc_dai->qmc_chan, direction); + ret = qmc_chan_stop(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; - ret = qmc_chan_reset(qmc_dai->qmc_chan, direction); + ret = qmc_chan_reset(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; break; case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = qmc_chan_stop(qmc_dai->qmc_chan, direction); + ret = qmc_chan_stop(qmc_dai->chan.qmc_chan, direction); if (ret) return ret; break; @@ -613,10 +635,10 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * if (!qmc_dai->name) return -ENOMEM; - qmc_dai->qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, - "fsl,qmc-chan"); - if (IS_ERR(qmc_dai->qmc_chan)) { - ret = PTR_ERR(qmc_dai->qmc_chan); + qmc_dai->chan.qmc_chan = devm_qmc_chan_get_byphandle(qmc_audio->dev, np, + "fsl,qmc-chan"); + if (IS_ERR(qmc_dai->chan.qmc_chan)) { + ret = PTR_ERR(qmc_dai->chan.qmc_chan); return dev_err_probe(qmc_audio->dev, ret, "dai %d get QMC channel failed\n", qmc_dai->id); } @@ -624,7 +646,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_soc_dai_driver->id = qmc_dai->id; qmc_soc_dai_driver->name = qmc_dai->name; - ret = qmc_chan_get_info(qmc_dai->qmc_chan, &info); + ret = qmc_chan_get_info(qmc_dai->chan.qmc_chan, &info); if (ret) { dev_err(qmc_audio->dev, "dai %d get QMC channel info failed %d\n", qmc_dai->id, ret);