From: Daniel Baluta <daniel.baluta@oss.nxp.com>
To: pierre-louis.bossart@linux.intel.com,
alsa-devel@alsa-project.org, kuninori.morimoto.gx@renesas.com,
peter.ujfalusi@ti.com, broonie@kernel.org, linux-imx@nxp.com,
robh+dt@kernel.org, devicetree@vger.kernel.org
Cc: Xiubo.Lee@gmail.com, shengjiu.wang@nxp.com,
linux-kernel@vger.kernel.org, tiwai@suse.com,
ranjani.sridharan@linux.intel.com,
liam.r.girdwood@linux.intel.com,
sound-open-firmware@alsa-project.org,
Daniel Baluta <daniel.baluta@nxp.com>
Subject: [PATCH v2 2/2] ASoC: fsl: Add generic CPU DAI driver
Date: Fri, 6 Mar 2020 13:13:53 +0200 [thread overview]
Message-ID: <20200306111353.12906-3-daniel.baluta@oss.nxp.com> (raw)
In-Reply-To: <20200306111353.12906-1-daniel.baluta@oss.nxp.com>
From: Daniel Baluta <daniel.baluta@nxp.com>
On i.MX8 platforms that have a DSP the DAI handling is taken care
of by two entities:
* Application Processor (AP), which runs Linux
* DSP, which runs a firmware (typically Sound Open Firmware)
The DSP has access to DAI IP registers, but it cannot easily handle
resources like:
* clocks
* power domain management
* pinctrl
For this reason we introduce a generic FSL DAI driver which will take
care of the resources above.
Signed-off-by: Daniel Baluta <daniel.baluta@nxp.com>
---
sound/soc/fsl/Kconfig | 8 ++
sound/soc/fsl/Makefile | 2 +
sound/soc/fsl/fsl_dai.c | 288 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 298 insertions(+)
create mode 100644 sound/soc/fsl/fsl_dai.c
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 65e8cd4be930..bea8ab2c24f9 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -75,6 +75,14 @@ config SND_SOC_FSL_ESAI
This option is only useful for out-of-tree drivers since
in-tree drivers select it automatically.
+config SND_SOC_FSL_DAI
+ tristate "Generic FSL DAI support for Sound Open Firmware"
+ help
+ Say Y if you want to enable generic FSL DAI support to be used
+ with Sound Open Firmware. This module takes care of enabling
+ clocks, power domain, pinctrl for FSL DAIs. The rest of DAI
+ control is taken care of by SOF firmware.
+
config SND_SOC_FSL_MICFIL
tristate "Pulse Density Modulation Microphone Interface (MICFIL) module support"
select REGMAP_MMIO
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile
index 8cde88c72d93..e4ed253b6657 100644
--- a/sound/soc/fsl/Makefile
+++ b/sound/soc/fsl/Makefile
@@ -20,6 +20,7 @@ snd-soc-fsl-ssi-y := fsl_ssi.o
snd-soc-fsl-ssi-$(CONFIG_DEBUG_FS) += fsl_ssi_dbg.o
snd-soc-fsl-spdif-objs := fsl_spdif.o
snd-soc-fsl-esai-objs := fsl_esai.o
+snd-soc-fsl-dai-objs := fsl_dai.o
snd-soc-fsl-micfil-objs := fsl_micfil.o
snd-soc-fsl-utils-objs := fsl_utils.o
snd-soc-fsl-dma-objs := fsl_dma.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o
obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o
obj-$(CONFIG_SND_SOC_FSL_SPDIF) += snd-soc-fsl-spdif.o
obj-$(CONFIG_SND_SOC_FSL_ESAI) += snd-soc-fsl-esai.o
+obj-$(CONFIG_SND_SOC_FSL_DAI) += snd-soc-fsl-dai.o
obj-$(CONFIG_SND_SOC_FSL_MICFIL) += snd-soc-fsl-micfil.o
obj-$(CONFIG_SND_SOC_FSL_UTILS) += snd-soc-fsl-utils.o
obj-$(CONFIG_SND_SOC_FSL_MQS) += snd-soc-fsl-mqs.o
diff --git a/sound/soc/fsl/fsl_dai.c b/sound/soc/fsl/fsl_dai.c
new file mode 100644
index 000000000000..804e04f87841
--- /dev/null
+++ b/sound/soc/fsl/fsl_dai.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Freescale Generic DAI driver for DSP
+//
+// Copyright 2019 NXP
+// Author: Daniel Baluta <daniel.baluta@nxp.com>
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_domain.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+enum fsl_dai_type {
+ FSL_DAI_TYPE_NONE,
+ FSL_DAI_TYPE_SAI,
+ FSL_DAI_TYPE_ESAI,
+};
+
+#define FSL_DAI_ESAI_CLK_NUM 4
+static const char *esai_clks[FSL_DAI_ESAI_CLK_NUM] = {
+ "core",
+ "extal",
+ "fsys",
+ "spba",
+};
+
+#define FSL_DAI_SAI_CLK_NUM 5
+static const char *sai_clks[FSL_DAI_SAI_CLK_NUM] = {
+ "bus",
+ "mclk0",
+ "mclk1",
+ "mclk2",
+ "mclk3",
+};
+
+struct fsl_dai {
+ struct platform_device *pdev;
+
+ /* DAI clocks */
+ struct clk **clks;
+ const char **clk_names;
+ int num_clks;
+
+ /* Power Domain handling */
+ int num_domains;
+ struct device **pd_dev;
+ struct device_link **link;
+
+ /* DAIS */
+ struct snd_soc_dai_driver *dai_drv;
+ int num_drv;
+};
+
+static struct snd_soc_dai_driver fsl_dai = {
+};
+
+static const struct snd_soc_component_driver fsl_dai_component = {
+ .name = "fsl-dai",
+};
+
+static int fsl_dai_init_clocks(struct fsl_dai *dai_priv)
+{
+ struct device *dev = &dai_priv->pdev->dev;
+ int i;
+
+ dai_priv->clks = devm_kcalloc(dev, dai_priv->num_clks,
+ sizeof(*dai_priv->clks), GFP_KERNEL);
+ if (!dai_priv->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < dai_priv->num_clks; i++) {
+ dai_priv->clks[i] = devm_clk_get(dev, dai_priv->clk_names[i]);
+ if (IS_ERR(dai_priv->clks[i])) {
+ dev_dbg(dev, "Failed to get clk %s\n",
+ dai_priv->clk_names[i]);
+ dai_priv->clks[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int fsl_get_dai_type(struct fsl_dai *dai_priv)
+{
+ struct device_node *np = dai_priv->pdev->dev.of_node;
+
+ if (of_device_is_compatible(np, "fsl,esai-dai"))
+ return FSL_DAI_TYPE_ESAI;
+
+ if (of_device_is_compatible(np, "fsl,sai-dai"))
+ return FSL_DAI_TYPE_SAI;
+
+ return FSL_DAI_TYPE_NONE;
+}
+
+static int fsl_dai_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct fsl_dai *priv;
+ char *dai_name;
+ int dai_type, dai_index;
+ int ret;
+ int i;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, priv);
+
+ ret = of_property_read_u32(np, "fsl,dai-index", &dai_index);
+ if (ret) {
+ dev_err(&pdev->dev, "dai-index missing or invalid\n");
+ return ret;
+ }
+
+ dai_type = fsl_get_dai_type(priv);
+ switch (dai_type) {
+ case FSL_DAI_TYPE_ESAI:
+ priv->clk_names = esai_clks;
+ priv->num_clks = FSL_DAI_ESAI_CLK_NUM;
+ priv->dai_drv = &fsl_dai;
+ priv->num_drv = 1;
+ dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "esai%d",
+ dai_index);
+ if (!dai_name)
+ return -ENOMEM;
+ break;
+ case FSL_DAI_TYPE_SAI:
+ priv->clk_names = sai_clks;
+ priv->num_clks = FSL_DAI_SAI_CLK_NUM;
+ priv->dai_drv = &fsl_dai;
+ priv->num_drv = 1;
+ dai_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "sai%d",
+ dai_index);
+ if (!dai_name)
+ return -ENOMEM;
+ break;
+ default:
+ dev_err(&pdev->dev, "Invalid DAI type %d\n", dai_type);
+ return -EINVAL;
+ }
+
+ fsl_dai.name = dai_name;
+
+ ret = fsl_dai_init_clocks(priv);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Error at init clocks\n");
+ return ret;
+ }
+
+ priv->num_domains = of_count_phandle_with_args(np, "power-domains",
+ "#power-domain-cells");
+ if (priv->num_domains < 0) {
+ dev_err(&pdev->dev, "no power-domains property in %pOF\n", np);
+ return priv->num_domains;
+ }
+
+ priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains,
+ sizeof(*priv->pd_dev), GFP_KERNEL);
+ if (!priv->pd_dev)
+ return -ENOMEM;
+
+ priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains,
+ sizeof(*priv->link), GFP_KERNEL);
+ if (!priv->link)
+ return -ENOMEM;
+
+ for (i = 0; i < priv->num_domains; i++) {
+ priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i);
+ if (IS_ERR(priv->pd_dev[i])) {
+ ret = PTR_ERR(priv->pd_dev[i]);
+ goto unroll_pm;
+ }
+
+ priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i],
+ DL_FLAG_STATELESS |
+ DL_FLAG_PM_RUNTIME |
+ DL_FLAG_RPM_ACTIVE);
+ if (!priv->link[i]) {
+ ret = -EINVAL;
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ goto unroll_pm;
+ }
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ ret = devm_snd_soc_register_component(&pdev->dev, &fsl_dai_component,
+ &fsl_dai, 1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register DAI ret = %d\n", ret);
+ return ret;
+ }
+ return 0;
+
+unroll_pm:
+ while (--i >= 0) {
+ device_link_del(priv->link[i]);
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ }
+ return ret;
+}
+
+static int fsl_dai_remove(struct platform_device *pdev)
+{
+ struct fsl_dai *priv = platform_get_drvdata(pdev);
+ int i;
+
+ pm_runtime_disable(&priv->pdev->dev);
+
+ for (i = 0; i < priv->num_domains; i++) {
+ device_link_del(priv->link[i]);
+ dev_pm_domain_detach(priv->pd_dev[i], false);
+ }
+
+ return 0;
+}
+
+static const struct of_device_id fsl_dai_dt_ids[] = {
+ { .compatible = "fsl,esai-dai", },
+ { .compatible = "fsl,sai-dai", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, fsl_dai_dt_ids);
+
+#ifdef CONFIG_PM
+static int fsl_dai_runtime_resume(struct device *dev)
+{
+ struct fsl_dai *priv = dev_get_drvdata(dev);
+ int i, ret;
+
+ for (i = 0; i < priv->num_clks; i++) {
+ ret = clk_prepare_enable(priv->clks[i]);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable clk %s\n",
+ priv->clk_names[i]);
+ goto out;
+ }
+ }
+ return 0;
+out:
+ while (--i >= 0)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return ret;
+}
+
+static int fsl_dai_runtime_suspend(struct device *dev)
+{
+ struct fsl_dai *priv = dev_get_drvdata(dev);
+ int i;
+
+ for (i = 0; i < priv->num_clks; i++)
+ clk_disable_unprepare(priv->clks[i]);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops fsl_dai_pm_ops = {
+ SET_RUNTIME_PM_OPS(fsl_dai_runtime_suspend,
+ fsl_dai_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static struct platform_driver fsl_dai_driver = {
+ .probe = fsl_dai_probe,
+ .remove = fsl_dai_remove,
+ .driver = {
+ .name = "fsl-dai",
+ .pm = &fsl_dai_pm_ops,
+ .of_match_table = fsl_dai_dt_ids,
+ },
+};
+
+module_platform_driver(fsl_dai_driver);
+
+MODULE_ALIAS("platform:fsl-dai");
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@nxp.com>");
+MODULE_DESCRIPTION("FSL Generic DAI driver for DSP");
+MODULE_LICENSE("GPL v2");
--
2.17.1
next prev parent reply other threads:[~2020-03-06 11:14 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-06 11:13 [PATCH v2 0/2] Add generic FSL CPU DAI driver Daniel Baluta
2020-03-06 11:13 ` [PATCH v2 1/2] dt-bindings: sound: Add FSL CPU DAI bindings Daniel Baluta
2020-03-12 20:23 ` Rob Herring
2020-03-16 13:01 ` Daniel Baluta
2020-03-18 23:50 ` Rob Herring
2020-03-06 11:13 ` Daniel Baluta [this message]
2020-03-16 15:10 ` [PATCH v2 2/2] ASoC: fsl: Add generic CPU DAI driver Lars-Peter Clausen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200306111353.12906-3-daniel.baluta@oss.nxp.com \
--to=daniel.baluta@oss.nxp.com \
--cc=Xiubo.Lee@gmail.com \
--cc=alsa-devel@alsa-project.org \
--cc=broonie@kernel.org \
--cc=daniel.baluta@nxp.com \
--cc=devicetree@vger.kernel.org \
--cc=kuninori.morimoto.gx@renesas.com \
--cc=liam.r.girdwood@linux.intel.com \
--cc=linux-imx@nxp.com \
--cc=linux-kernel@vger.kernel.org \
--cc=peter.ujfalusi@ti.com \
--cc=pierre-louis.bossart@linux.intel.com \
--cc=ranjani.sridharan@linux.intel.com \
--cc=robh+dt@kernel.org \
--cc=shengjiu.wang@nxp.com \
--cc=sound-open-firmware@alsa-project.org \
--cc=tiwai@suse.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).