Received: by 2002:a05:6a10:8c0a:0:0:0:0 with SMTP id go10csp254743pxb; Thu, 25 Feb 2021 01:22:55 -0800 (PST) X-Google-Smtp-Source: ABdhPJwRBUFE8WCIo+w9+HVUsW+puNdnZQYSxhW40a6/Nle1iKLCgy10M20tHS5EjQkT/XMbOH6X X-Received: by 2002:a17:906:b14b:: with SMTP id bt11mr1871225ejb.162.1614244975699; Thu, 25 Feb 2021 01:22:55 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1614244975; cv=none; d=google.com; s=arc-20160816; b=smfq3MjgTbPkiij0UW9IN5vucBBmlDq4HA9oUCdO0OehD6bWfPB1yJ1oSxVf1BH9Yv +90Pm3Ez63176gF0DizqR0Fw+j7boghsB90xQGgHSP5SlTMp/J9+U/yBsMbvipzuZVnY M7XR0IpunDlG0mRyQ23M2CYqbHk0ERci0DB/qAceSlAZxATZTbkguNeJR6EdnAME6WS3 S76kIkfJ0f6RuZy2HSqjnXwK/sZp2o5VKt4GfEf1T6IZ3CxM+yq0goQastxHQy1C9SqQ vu9arCW4YvnV0JFSjrBCZnpSfhqPlqZnjCPikyy70U8H2HzPy/AUEem+atctyP1NJo6w Ix0Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:references:in-reply-to:message-id:date:subject :to:from; bh=BJ9HadZGoo9zdQvt9UD+96jtKmITQWw3aOSfnkp0hK8=; b=tDdxSn0pYzr8lL8zJJ/8LxLdjn1lOYDvAMKmPHkHTTKkmjSkP1f+H37qJw2imiXT/K A2zBxGx3xsWoqy8Kv1aNaKW/jeLR87+CXf39/GsPpivSMhiCAJn7Tbr+RdbEQiBiDkvF bgNsejFzgq4bCEewbipeGJ8I1F84oOxGPNwi+yxHWft18Dc30K03ASV5P/aapahMqXPl LuphKYco9HMg0CekuL7XC9sfQ4L+IeONpBg1ZhK+fSz7CdgFEyyAgS5t23+lKFQd4RQg N0HP6iZGbHVGGk/9R46pgHGjTTGBR4GBznKFZ+61fZAY7cKWcaaNYMIr3yqP3zwLOcc3 ViAQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id v1si3010202edb.592.2021.02.25.01.22.26; Thu, 25 Feb 2021 01:22:55 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=nxp.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236952AbhBYDGc (ORCPT + 99 others); Wed, 24 Feb 2021 22:06:32 -0500 Received: from inva020.nxp.com ([92.121.34.13]:35632 "EHLO inva020.nxp.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236902AbhBYDGL (ORCPT ); Wed, 24 Feb 2021 22:06:11 -0500 Received: from inva020.nxp.com (localhost [127.0.0.1]) by inva020.eu-rdc02.nxp.com (Postfix) with ESMTP id 4FBE21A0629; Thu, 25 Feb 2021 04:05:23 +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 78B9E1A0624; Thu, 25 Feb 2021 04:05:16 +0100 (CET) Received: from localhost.localdomain (shlinux2.ap.freescale.net [10.192.224.44]) by invc005.ap-rdc01.nxp.com (Postfix) with ESMTP id B8ECC40327; Thu, 25 Feb 2021 04:05:08 +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 v3 2/7] ASoC: fsl_rpmsg: Add CPU DAI driver for audio base on rpmsg Date: Thu, 25 Feb 2021 10:52:38 +0800 Message-Id: <1614221563-26822-3-git-send-email-shengjiu.wang@nxp.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1614221563-26822-1-git-send-email-shengjiu.wang@nxp.com> References: <1614221563-26822-1-git-send-email-shengjiu.wang@nxp.com> X-Virus-Scanned: ClamAV using ClamSMTP Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- sound/soc/fsl/Kconfig | 7 + sound/soc/fsl/Makefile | 2 + sound/soc/fsl/fsl_rpmsg.c | 261 ++++++++++++++++++++++++++++++++++++++ sound/soc/fsl/fsl_rpmsg.h | 40 ++++++ 4 files changed, 310 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..a688c3c2efbc 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 "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..1082a3b3a18d --- /dev/null +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -0,0 +1,261 @@ +// 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; + unsigned int 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; + + 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, + .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..8d380d172b4b --- /dev/null +++ b/sound/soc/fsl/fsl_rpmsg.h @@ -0,0 +1,40 @@ +/* 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 + * @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; + unsigned int mclk_streams; + int force_lpa; + int enable_lpa; + int buffer_size; + int audioindex; + int version; +}; +#endif /* __FSL_RPMSG_H */ -- 2.27.0