From patchwork Mon Jun 22 14:31:09 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud POULIQUEN X-Patchwork-Id: 6655901 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 6CE189F380 for ; Mon, 22 Jun 2015 14:35:36 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A40F8205C1 for ; Mon, 22 Jun 2015 14:35:30 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 28BC7203ED for ; Mon, 22 Jun 2015 14:35:29 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id 652B2265152; Mon, 22 Jun 2015 16:35:28 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,NO_DNS_FOR_FROM, UNPARSEABLE_RELAY autolearn=no version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 59E272652CE; Mon, 22 Jun 2015 16:33:04 +0200 (CEST) X-Original-To: alsa-devel@alsa-project.org Delivered-To: alsa-devel@alsa-project.org Received: by alsa0.perex.cz (Postfix, from userid 1000) id 2BDE72652C3; Mon, 22 Jun 2015 16:33:03 +0200 (CEST) Received: from mx08-00178001.pphosted.com (mx08-00178001.pphosted.com [91.207.212.93]) by alsa0.perex.cz (Postfix) with ESMTP id CE3AE265122 for ; Mon, 22 Jun 2015 16:31:41 +0200 (CEST) Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx08-00178001.pphosted.com (8.14.5/8.14.5) with SMTP id t5MERhOE009233; Mon, 22 Jun 2015 16:31:40 +0200 Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx08-00178001.pphosted.com with ESMTP id 1v5qkk6j1d-1 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT); Mon, 22 Jun 2015 16:31:40 +0200 Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 7A3326F; Mon, 22 Jun 2015 14:31:38 +0000 (GMT) Received: from Webmail-eu.st.com (Safex1hubcas22.st.com [10.75.90.92]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 5FCB0AA45; Mon, 22 Jun 2015 14:31:38 +0000 (GMT) Received: from localhost (10.201.23.162) by Webmail-ga.st.com (10.75.90.48) with Microsoft SMTP Server (TLS) id 14.3.195.1; Mon, 22 Jun 2015 16:31:38 +0200 From: Arnaud Pouliquen To: Date: Mon, 22 Jun 2015 16:31:09 +0200 Message-ID: <1434983473-25092-6-git-send-email-arnaud.pouliquen@st.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1434983473-25092-1-git-send-email-arnaud.pouliquen@st.com> References: <1434983473-25092-1-git-send-email-arnaud.pouliquen@st.com> MIME-Version: 1.0 X-Originating-IP: [10.201.23.162] X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:5.14.151, 1.0.33, 0.0.0000 definitions=2015-06-22_02:2015-06-22, 2015-06-22, 1970-01-01 signatures=0 Cc: broonie@kernel.org, arnaud.pouliquen@st.com, lgirdwood@gmail.com, kernel@stlinux.com Subject: [alsa-devel] [PATCH v3 5/9] ASoC: sti: Add uniperipheral dai driver X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.14 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-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP ASoc uniperipheral dai driver that manages uniperipheral DAIs and registers associated generic dma engine platform. Signed-off-by: Arnaud Pouliquen --- sound/soc/sti/sti_uniperif.c | 254 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sti/uniperif.h | 11 +- 2 files changed, 264 insertions(+), 1 deletion(-) create mode 100644 sound/soc/sti/sti_uniperif.c diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c new file mode 100644 index 0000000..427c055 --- /dev/null +++ b/sound/soc/sti/sti_uniperif.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include "uniperif.h" + +/* + * sti_uniperiph_dai_create_ctrl + * This function is used to create Ctrl associated to DAI but also pcm device. + * Request is done by front end to associate ctrl with pcm device id + */ +int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + struct snd_kcontrol_new *ctrl; + int i; + + if (!uni->num_ctrls) + return 0; + + for (i = 0; i < uni->num_ctrls; i++) { + /* + * Several Control can have same name. Controls are indexed on + * Uniperipheral instance ID + */ + ctrl = &uni->snd_ctrls[i]; + ctrl->index = uni->info->id; + ctrl->device = uni->info->id; + } + + return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); +} + +/* + * DAI + */ +int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_dmaengine_dai_dma_data *dma_data; + int transfer_size; + + transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; + + dma_data = snd_soc_dai_get_dma_data(dai, substream); + dma_data->maxburst = transfer_size; + + return 0; +} + +int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + + priv->dai_data.uni->daifmt = fmt; + + return 0; +} + +static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + int ret; + + /* The uniperipheral should be in stopped state */ + if (uni->state != UNIPERIF_STATE_STOPPED) { + dev_err(uni->dev, "%s: invalid uni state( %d)", + __func__, (int)uni->state); + return -EBUSY; + } + + /* Pinctrl: switch pinstate to sleep */ + ret = pinctrl_pm_select_sleep_state(uni->dev); + if (ret) + dev_err(uni->dev, "%s: failed to select pinctrl state", + __func__); + + return ret; +} + +static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + int ret; + + if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { + ret = uni_player_resume(uni); + if (ret) + return ret; + } + + /* pinctrl: switch pinstate to default */ + ret = pinctrl_pm_select_default_state(uni->dev); + if (ret) + dev_err(uni->dev, "%s: failed to select pinctrl state", + __func__); + + return ret; +} + +static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct sti_uniperiph_dai *dai_data = &priv->dai_data; + + /* DMA settings*/ + if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) + snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); + else + snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); + + dai_data->dma_data.addr = dai_data->uni->fifo_phys_address; + dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + return sti_uniperiph_dai_create_ctrl(dai); +} + +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .probe = sti_uniperiph_dai_probe, + .suspend = sti_uniperiph_dai_suspend, + .resume = sti_uniperiph_dai_resume +}; + +static const struct snd_soc_component_driver sti_uniperiph_dai_component = { + .name = "sti_cpu_dai", +}; + +static int sti_uniperiph_cpu_dai_of(struct device_node *node, + struct sti_uniperiph_data *priv) +{ + const char *str; + int ret; + struct device *dev = &priv->pdev->dev; + struct sti_uniperiph_dai *dai_data = &priv->dai_data; + struct snd_soc_dai_driver *dai = priv->dai; + struct snd_soc_pcm_stream *stream; + struct uniperif *uni; + + uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); + if (!uni) + return -ENOMEM; + + *dai = sti_uniperiph_dai_template; + ret = of_property_read_string(node, "dai-name", &str); + if (ret < 0) { + dev_err(dev, "%s: dai name missing.\n", __func__); + return -EINVAL; + } + dai->name = str; + + /* Get resources */ + uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); + + if (!uni->mem_region) { + dev_err(dev, "Failed to get memory resource"); + return -ENODEV; + } + + uni->base = devm_ioremap_resource(dev, uni->mem_region); + + if (IS_ERR(uni->base)) + return PTR_ERR(uni->base); + + uni->fifo_phys_address = uni->mem_region->start + + UNIPERIF_FIFO_DATA_OFFSET(uni); + + uni->irq = platform_get_irq(priv->pdev, 0); + if (!uni->irq < 0) { + dev_err(dev, "Failed to get IRQ resource"); + return -ENXIO; + } + + dai_data->uni = uni; + + if (of_device_is_compatible(node, "st,sti-uni-player")) { + uni_player_init(priv->pdev, uni); + stream = &dai->playback; + } else { + uni_reader_init(priv->pdev, uni); + stream = &dai->capture; + } + dai->ops = uni->dai_ops; + + stream->stream_name = dai->name; + stream->channels_min = uni->hw->channels_min; + stream->channels_max = uni->hw->channels_max; + stream->rates = uni->hw->rates; + stream->formats = uni->hw->formats; + + return 0; +} + +static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, +}; + +static int sti_uniperiph_probe(struct platform_device *pdev) +{ + struct sti_uniperiph_data *priv; + struct device_node *node = pdev->dev.of_node; + int ret; + + /* Allocate the private data and the CPU_DAI array */ + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL); + if (!priv->dai) + return -ENOMEM; + + priv->pdev = pdev; + + ret = sti_uniperiph_cpu_dai_of(node, priv); + + dev_set_drvdata(&pdev->dev, priv); + + ret = snd_soc_register_component(&pdev->dev, + &sti_uniperiph_dai_component, + priv->dai, 1); + if (ret < 0) + return ret; + + return devm_snd_dmaengine_pcm_register(&pdev->dev, + &dmaengine_pcm_config, 0); +} + +static const struct of_device_id snd_soc_sti_match[] = { + { .compatible = "st,sti-uni-player", }, + { .compatible = "st,sti-uni-reader", }, + {}, +}; + +static struct platform_driver sti_uniperiph_driver = { + .driver = { + .name = "sti-uniperiph-dai", + .owner = THIS_MODULE, + .of_match_table = snd_soc_sti_match, + }, + .probe = sti_uniperiph_probe, +}; +module_platform_driver(sti_uniperiph_driver); + +MODULE_DESCRIPTION("uniperipheral DAI driver"); +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f396958..9c4f75c 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1211,8 +1211,17 @@ struct sti_uniperiph_data { int uni_player_init(struct platform_device *pdev, struct uniperif *uni_player); int uni_player_resume(struct uniperif *player); - +5d43b60ad849dfc2a3ff063477deab73866b12dd /* uniperiph reader */ int uni_reader_init(struct platform_device *pdev, struct uniperif *uni_reader); + +/* common */ +int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt); + +int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + #endif