From patchwork Mon Mar 8 13:22:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shengjiu Wang X-Patchwork-Id: 395529 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, URIBL_BLOCKED, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 852DCC433DB for ; Mon, 8 Mar 2021 13:37:44 +0000 (UTC) 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 mail.kernel.org (Postfix) with ESMTPS id EEF6E651C2 for ; Mon, 8 Mar 2021 13:37:43 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EEF6E651C2 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=nxp.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org 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 8357C188F; Mon, 8 Mar 2021 14:36:52 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 8357C188F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1615210662; bh=rlZmke1WFLf4xZs5ZW8e3hDPMdgTnuTmsFpwBgkUe5I=; h=From:To:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=ZEFsZCzeNxhg/LIDGXhsHmhZtX4DT17byrpKqm2MpDQIWZYcHtzrMtNp/FOjBzrFb ez7yl/ikXG/VWhxvFj1qXNKh8MLVibWNTc1Nd5HXWjluP8Dk1GC8bcbC3MOdZzd9hc eEEmhnHyUP/E11cjA2ZWiKKxWz7kpzM3H5ZfrqT4= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 999D8F80431; Mon, 8 Mar 2021 14:35:51 +0100 (CET) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 3BD49F80423; Mon, 8 Mar 2021 14:35:50 +0100 (CET) Received: from inva020.nxp.com (inva020.nxp.com [92.121.34.13]) (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 36632F800D0 for ; Mon, 8 Mar 2021 14:35:37 +0100 (CET) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 36632F800D0 Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id C3C421A0BB5; Mon, 8 Mar 2021 14:35:36 +0100 (CET) Received: from invc005.ap-rdc01.nxp.com (invc005.ap-rdc01.nxp.com [165.114.16.14]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id E777A1A0BA9; Mon, 8 Mar 2021 14:35:29 +0100 (CET) Received: from localhost.localdomain (shlinux2.ap.freescale.net [10.192.224.44]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id 22781402EB; Mon, 8 Mar 2021 14:35:21 +0100 (CET) From: Shengjiu Wang To: lgirdwood@gmail.com, broonie@kernel.org, perex@perex.cz, tiwai@suse.com, alsa-devel@alsa-project.org, linux-kernel@vger.kernel.org, timur@kernel.org, nicoleotsuka@gmail.com, Xiubo.Lee@gmail.com, festevam@gmail.com, linuxppc-dev@lists.ozlabs.org, robh+dt@kernel.org, devicetree@vger.kernel.org Subject: [PATCH v4 2/6] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg Date: Mon, 8 Mar 2021 21:22:26 +0800 Message-Id: <1615209750-2357-3-git-send-email-shengjiu.wang@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1615209750-2357-1-git-send-email-shengjiu.wang@nxp.com> References: <1615209750-2357-1-git-send-email-shengjiu.wang@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP 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" This is a cpu dai driver for rpmsg audio use case, which is mainly used for getting the user's configuration from devicetree and configure the clocks which is used by Cortex-M core. Signed-off-by: Shengjiu Wang Reported-by: kernel test robot --- sound/soc/fsl/Kconfig | 7 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_rpmsg.c | 283 ++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_rpmsg.h | 42 ++++++ 4 files changed, 334 insertions(+) create mode 100644 sound/soc/fsl/fsl_rpmsg.c create mode 100644 sound/soc/fsl/fsl_rpmsg.h diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index d7f30036d434..f833856f6de0 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -115,6 +115,13 @@ config SND_SOC_FSL_AUD2HTX config SND_SOC_FSL_UTILS tristate +config SND_SOC_FSL_RPMSG + tristate "NXP Audio Base On RPMSG support" + help + Say Y if you want to add rpmsg audio support for the Freescale CPUs. + This option is only useful for out-of-tree drivers since + in-tree drivers select it automatically. + config SND_SOC_IMX_PCM_DMA tristate select SND_SOC_GENERIC_DMAENGINE_PCM diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 8c5fa8a859c0..b63802f345cc 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile @@ -27,6 +27,7 @@ snd-soc-fsl-mqs-objs := fsl_mqs.o snd-soc-fsl-easrc-objs := fsl_easrc.o snd-soc-fsl-xcvr-objs := fsl_xcvr.o snd-soc-fsl-aud2htx-objs := fsl_aud2htx.o +snd-soc-fsl-rpmsg-objs := fsl_rpmsg.o obj-$(CONFIG_SND_SOC_FSL_AUDMIX) += snd-soc-fsl-audmix.o obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o @@ -42,6 +43,7 @@ obj-$(CONFIG_SND_SOC_FSL_EASRC) += snd-soc-fsl-easrc.o obj-$(CONFIG_SND_SOC_POWERPC_DMA) += snd-soc-fsl-dma.o obj-$(CONFIG_SND_SOC_FSL_XCVR) += snd-soc-fsl-xcvr.o obj-$(CONFIG_SND_SOC_FSL_AUD2HTX) += snd-soc-fsl-aud2htx.o +obj-$(CONFIG_SND_SOC_FSL_RPMSG) += snd-soc-fsl-rpmsg.o # MPC5200 Platform Support obj-$(CONFIG_SND_MPC52xx_DMA) += mpc5200_dma.o diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c new file mode 100644 index 000000000000..35b3ee376338 --- /dev/null +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -0,0 +1,283 @@ +// SPDX-License-Identifier: GPL-2.0+ +// Copyright 2018-2021 NXP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fsl_rpmsg.h" +#include "imx-pcm.h" + +#define FSL_RPMSG_RATES (SNDRV_PCM_RATE_8000 | \ + SNDRV_PCM_RATE_16000 | \ + SNDRV_PCM_RATE_48000) +#define FSL_RPMSG_FORMATS SNDRV_PCM_FMTBIT_S16_LE + +static const unsigned int fsl_rpmsg_rates[] = { + 8000, 11025, 16000, 22050, 44100, + 32000, 48000, 96000, 88200, 176400, 192000, + 352800, 384000, 705600, 768000, 1411200, 2822400, +}; + +static const struct snd_pcm_hw_constraint_list fsl_rpmsg_rate_constraints = { + .count = ARRAY_SIZE(fsl_rpmsg_rates), + .list = fsl_rpmsg_rates, +}; + +static int fsl_rpmsg_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai); + struct clk *p = rpmsg->mclk, *pll = 0, *npll = 0; + u64 rate = params_rate(params); + int ret = 0; + + /* Get current pll parent */ + while (p && rpmsg->pll8k && rpmsg->pll11k) { + struct clk *pp = clk_get_parent(p); + + if (clk_is_match(pp, rpmsg->pll8k) || + clk_is_match(pp, rpmsg->pll11k)) { + pll = pp; + break; + } + p = pp; + } + + /* Switch to another pll parent if needed. */ + if (pll) { + npll = (do_div(rate, 8000) ? rpmsg->pll11k : rpmsg->pll8k); + if (!clk_is_match(pll, npll)) { + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(dai->dev, "failed to set parent %s: %d\n", + __clk_get_name(npll), ret); + } + } + + if (!(rpmsg->mclk_streams & BIT(substream->stream))) { + ret = clk_prepare_enable(rpmsg->mclk); + if (ret) { + dev_err(dai->dev, "failed to enable mclk: %d\n", ret); + return ret; + } + + rpmsg->mclk_streams |= BIT(substream->stream); + } + + return ret; +} + +static int fsl_rpmsg_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct fsl_rpmsg *rpmsg = snd_soc_dai_get_drvdata(dai); + + if (rpmsg->mclk_streams & BIT(substream->stream)) { + clk_disable_unprepare(rpmsg->mclk); + rpmsg->mclk_streams &= ~BIT(substream->stream); + } + + return 0; +} + +static int fsl_rpmsg_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *cpu_dai) +{ + int ret; + + ret = snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &fsl_rpmsg_rate_constraints); + + return ret; +} + +static const struct snd_soc_dai_ops fsl_rpmsg_dai_ops = { + .startup = fsl_rpmsg_startup, + .hw_params = fsl_rpmsg_hw_params, + .hw_free = fsl_rpmsg_hw_free, +}; + +static struct snd_soc_dai_driver fsl_rpmsg_dai = { + .playback = { + .stream_name = "CPU-Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_RPMSG_FORMATS, + }, + .capture = { + .stream_name = "CPU-Capture", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = FSL_RPMSG_FORMATS, + }, + .symmetric_rate = 1, + .symmetric_channels = 1, + .symmetric_sample_bits = 1, + .ops = &fsl_rpmsg_dai_ops, +}; + +static const struct snd_soc_component_driver fsl_component = { + .name = "fsl-rpmsg", +}; + +static const struct of_device_id fsl_rpmsg_ids[] = { + { .compatible = "fsl,imx7ulp-rpmsg"}, + { .compatible = "fsl,imx8mm-rpmsg"}, + { .compatible = "fsl,imx8mn-rpmsg"}, + { .compatible = "fsl,imx8mp-rpmsg"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fsl_rpmsg_ids); + +static int fsl_rpmsg_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct fsl_rpmsg *rpmsg; + int ret; + + rpmsg = devm_kzalloc(&pdev->dev, sizeof(struct fsl_rpmsg), GFP_KERNEL); + if (!rpmsg) + return -ENOMEM; + + ret = of_property_read_u32(np, "fsl,audioindex", &rpmsg->audioindex); + if (ret) + rpmsg->audioindex = 0; + + if (of_property_read_u32(np, "fsl,buffer-size", &rpmsg->buffer_size)) + rpmsg->buffer_size = IMX_DEFAULT_DMABUF_SIZE; + + if (of_property_read_bool(pdev->dev.of_node, "fsl,enable-lpa")) + rpmsg->enable_lpa = 1; + + ret = of_property_read_u32(np, "fsl,version", &rpmsg->version); + if (ret) + rpmsg->version = API_VERSION_V2; + + /*Get the optional clocks */ + rpmsg->ipg = devm_clk_get(&pdev->dev, "ipg"); + if (IS_ERR(rpmsg->ipg)) + rpmsg->ipg = NULL; + + rpmsg->mclk = devm_clk_get(&pdev->dev, "mclk"); + if (IS_ERR(rpmsg->mclk)) + rpmsg->mclk = NULL; + + rpmsg->dma = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(rpmsg->dma)) + rpmsg->dma = NULL; + + rpmsg->pll8k = devm_clk_get(&pdev->dev, "pll8k"); + if (IS_ERR(rpmsg->pll8k)) + rpmsg->pll8k = NULL; + + rpmsg->pll11k = devm_clk_get(&pdev->dev, "pll11k"); + if (IS_ERR(rpmsg->pll11k)) + rpmsg->pll11k = NULL; + + platform_set_drvdata(pdev, rpmsg); + pm_runtime_enable(&pdev->dev); + + ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, + &fsl_rpmsg_dai, 1); + if (ret) + return ret; + + rpmsg->card_pdev = platform_device_register_data(&pdev->dev, + "imx-audio-rpmsg", + PLATFORM_DEVID_NONE, + NULL, + 0); + if (IS_ERR(rpmsg->card_pdev)) { + dev_err(&pdev->dev, "failed to register rpmsg card\n"); + ret = PTR_ERR(rpmsg->card_pdev); + return ret; + } + + return 0; +} + +static int fsl_rpmsg_remove(struct platform_device *pdev) +{ + struct fsl_rpmsg *rpmsg = platform_get_drvdata(pdev); + + if (rpmsg->card_pdev) + platform_device_unregister(rpmsg->card_pdev); + + return 0; +} + +#ifdef CONFIG_PM +static int fsl_rpmsg_runtime_resume(struct device *dev) +{ + struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(rpmsg->ipg); + if (ret) { + dev_err(dev, "failed to enable ipg clock: %d\n", ret); + goto ipg_err; + } + + ret = clk_prepare_enable(rpmsg->dma); + if (ret) { + dev_err(dev, "Failed to enable dma clock %d\n", ret); + goto dma_err; + } + + return 0; + +dma_err: + clk_disable_unprepare(rpmsg->ipg); +ipg_err: + return ret; +} + +static int fsl_rpmsg_runtime_suspend(struct device *dev) +{ + struct fsl_rpmsg *rpmsg = dev_get_drvdata(dev); + + clk_disable_unprepare(rpmsg->dma); + clk_disable_unprepare(rpmsg->ipg); + + return 0; +} +#endif + +static const struct dev_pm_ops fsl_rpmsg_pm_ops = { + SET_RUNTIME_PM_OPS(fsl_rpmsg_runtime_suspend, + fsl_rpmsg_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver fsl_rpmsg_driver = { + .probe = fsl_rpmsg_probe, + .remove = fsl_rpmsg_remove, + .driver = { + .name = "fsl_rpmsg", + .pm = &fsl_rpmsg_pm_ops, + .of_match_table = fsl_rpmsg_ids, + }, +}; +module_platform_driver(fsl_rpmsg_driver); + +MODULE_DESCRIPTION("Freescale SoC Audio PRMSG CPU Interface"); +MODULE_AUTHOR("Shengjiu Wang "); +MODULE_ALIAS("platform:fsl_rpmsg"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/fsl/fsl_rpmsg.h b/sound/soc/fsl/fsl_rpmsg.h new file mode 100644 index 000000000000..c6dd3dde3293 --- /dev/null +++ b/sound/soc/fsl/fsl_rpmsg.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright 2017-2021 NXP + */ + +#ifndef __FSL_RPMSG_H +#define __FSL_RPMSG_H + +#define API_VERSION_V1 1 +#define API_VERSION_V2 2 + +/* + * struct fsl_rpmsg - rpmsg private data + * + * @ipg: ipg clock for cpu dai (SAI) + * @mclk: master clock for cpu dai (SAI) + * @dma: clock for dma device + * @pll8k: parent clock for multiple of 8kHz frequency + * @pll11k: parent clock for multiple of 11kHz frequency + * @card_pdev: Platform_device pointer to register a sound card + * @mclk_streams: Active streams that are using baudclk + * @force_lpa: force enable low power audio routine if condition satisfy + * @enable_lpa: enable low power audio routine according to dts setting + * @buffer_size: pre allocated dma buffer size + * @audioindex: audio instance index + * @version: rpmsg image version + */ +struct fsl_rpmsg { + struct clk *ipg; + struct clk *mclk; + struct clk *dma; + struct clk *pll8k; + struct clk *pll11k; + struct platform_device *card_pdev; + unsigned int mclk_streams; + int force_lpa; + int enable_lpa; + int buffer_size; + int audioindex; + int version; +}; +#endif /* __FSL_RPMSG_H */