From: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
To: Kenneth Westfield <kwestfie@codeaurora.org>,
ALSA Mailing List <alsa-devel@alsa-project.org>,
Device Tree Mailing List <devicetree@vger.kernel.org>,
MSM Mailing List <linux-arm-msm@vger.kernel.org>
Cc: Banajit Goswami <bgoswami@codeaurora.org>,
Takashi Iwai <tiwai@suse.de>,
Greg KH <gregkh@linuxfoundation.org>,
Patrick Lai <plai@codeaurora.org>,
Liam Girdwood <lgirdwood@gmail.com>,
Rob Herring <rob.herring@calxeda.com>,
Bryan Huntsman <bryanh@codeaurora.org>,
Mark Brown <broonie@kernel.org>,
David Brown <davidb@codeaurora.org>
Subject: Re: [PATCH 4/9] ASoC: ipq806x: Add LPASS CPU DAI driver
Date: Wed, 19 Nov 2014 15:17:06 -0600 [thread overview]
Message-ID: <546D08D2.5030808@linux.intel.com> (raw)
In-Reply-To: <1416423169-21865-5-git-send-email-kwestfie@codeaurora.org>
On 11/19/14, 12:52 PM, Kenneth Westfield wrote:
> From: Kenneth Westfield <kwestfie@codeaurora.org>
>
> Add the CPU DAI driver for the QCOM LPASS SOC.
>
> Change-Id: I64ac4407dd32bb9a3066d4b7427292002eaf5d14
> Signed-off-by: Kenneth Westfield <kwestfie@codeaurora.org>
> Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org>
> ---
> sound/soc/qcom/lpass-cpu-dai.c | 307 +++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 307 insertions(+)
> create mode 100644 sound/soc/qcom/lpass-cpu-dai.c
>
> diff --git a/sound/soc/qcom/lpass-cpu-dai.c b/sound/soc/qcom/lpass-cpu-dai.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..0693e761e01fd416f52684977bcfaf1579dc259c
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-cpu-dai.c
> @@ -0,0 +1,307 @@
> +/*
> + * Copyright (c) 2010-2011,2013-2014 The Linux Foundation. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 and
> + * only version 2 as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <sound/soc.h>
> +#include <sound/pcm_params.h>
> +#include "lpass-lpaif.h"
> +#include "lpass-pcm-mi2s.h"
> +
> +#define DRV_NAME "lpass-cpu-dai"
> +#define DRV_VERSION "1.0"
> +
> +#define LPASS_INVALID (-1)
> +
> +struct mi2s_hw_params {
> + uint8_t channels;
> + uint32_t freq;
> + uint8_t bit_width;
> +};
> +
> +static struct clk *lpaif_mi2s_bit_clk;
> +static struct clk *lpaif_mi2s_osr_clk;
> +static struct mi2s_hw_params mi2s_params;
> +
> +/*
> + * Returns the OSR to BIT clock divider that would be used with the given
> + * stream characteristics.
> + */
> +static uint32_t lpass_cpu_get_bit_div(uint32_t samp_freq, uint32_t bit_width,
> + uint32_t channels)
> +{
> + if (channels == 8) {
> + if (bit_width == 24 &&
> + ((samp_freq != 176400) &&
> + (samp_freq != 192000)))
> + return 2;
> + return 1;
> + } else if (channels == 6) {
> + if ((bit_width == 32 && ((samp_freq == 176400) ||
> + (samp_freq == 192000))) || (bit_width == 24 &&
> + (samp_freq == 192000)))
> + return 1;
> + else
> + return 2;
> + }
> +
> + switch (samp_freq) {
> + case 8000:
> + case 16000:
> + case 32000:
> + case 64000:
> + if (bit_width == 16)
> + return 4;
Does this test have any value? the behavior is identical in all cases.
> + break;
> + case 48000:
> + if (bit_width == 24)
> + return 4;
same.
> + break;
> + case 96000:
> + case 192000:
> + return 4;
> + case 176400:
> + return 2;
> + case 11025:
> + case 22050:
> + case 44100:
> + case 88200:
> + default:
> + pr_err("%s: Invalid PCM format given\n", __func__);
> + return LPASS_INVALID;
> + }
> +
> + return 4;
> +}
> +
> +static int lpass_cpu_mi2s_hw_params(struct snd_pcm_substream *substream,
> + struct snd_pcm_hw_params *params,
> + struct snd_soc_dai *dai)
> +{
> + uint32_t ret = 0;
> + uint32_t bit_act;
> + uint16_t bit_div;
> + uint32_t bit_width = params_format(params);
> + uint32_t channels = params_channels(params);
> + uint32_t rate = params_rate(params);
> + struct snd_pcm_runtime *runtime = substream->runtime;
> + struct lpass_runtime_data_t *prtd = runtime->private_data;
> + struct mi2s_hw_params curr_params;
> +
> + bit_act = snd_pcm_format_width(bit_width);
> + if (bit_act == LPASS_INVALID) {
> + dev_err(dai->dev, "%s: Invalid bit width given\n", __func__);
> + return -EINVAL;
> + }
> +
> + prtd->pcm_stream_info.bit_width = bit_act;
> + curr_params.freq = rate;
> + curr_params.channels = channels;
> + curr_params.bit_width = bit_act;
> +
> + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> + /* disable SPKR to make sure it will start in sane state */
> + lpaif_cfg_i2s_playback(0, 0, LPAIF_MI2S);
> +
> + /*
> + * Set channel info, it will take effect only if SPKR is
> + * enabled
> + */
> + ret = lpaif_cfg_mi2s_playback_hwparams_channels(channels,
> + LPAIF_MI2S, bit_act);
> + } else {
> + dev_err(dai->dev, "%s: Invalid stream direction\n", __func__);
> + return -EINVAL;
> + }
> +
> + /* Make sure our channel setting was success */
> + if (ret) {
> + /* shutdown would be called where we restore stuff */
> + dev_err(dai->dev, "%s: Channel setting unsuccessful\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + mi2s_params.freq = rate;
> + mi2s_params.channels = channels;
> + mi2s_params.bit_width = bit_act;
> +
> + ret = lpaif_cfg_mi2s_hwparams_bit_width(bit_width, LPAIF_MI2S);
> + if (ret) {
> + dev_err(dai->dev, "%s: Could not set bit width in HW\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + bit_div = lpass_cpu_get_bit_div(rate, bit_act, channels);
> + if (bit_div == LPASS_INVALID) {
> + dev_err(dai->dev, "%s: Could not get bit clk divider\n",
> + __func__);
> + return -EINVAL;
> + }
> +
> + ret = clk_set_rate(lpaif_mi2s_osr_clk,
> + (rate * bit_act * channels * bit_div));
> + if (ret) {
> + dev_err(dai->dev, "%s: error in setting mi2s osr clk\n",
> + __func__);
> + return ret;
> + }
> + ret = clk_prepare_enable(lpaif_mi2s_osr_clk);
> + if (ret) {
> + dev_err(dai->dev, "%s: error in enabling mi2s osr clk\n",
> + __func__);
> + return ret;
> + }
> + prtd->lpaif_clk.is_osr_clk_enabled = 1;
> +
> + ret = clk_set_rate(lpaif_mi2s_bit_clk, rate * bit_act * channels);
> + if (ret) {
> + dev_err(dai->dev, "%s: error in setting mi2s bit clk\n",
> + __func__);
> + return ret;
> + }
> + ret = clk_prepare_enable(lpaif_mi2s_bit_clk);
> + if (ret) {
> + dev_err(dai->dev, "%s: error in enabling mi2s bit clk\n",
> + __func__);
> + return ret;
> + }
> + prtd->lpaif_clk.is_bit_clk_enabled = 1;
> +
> + return 0;
> +}
> +
> +static int lpass_cpu_mi2s_prepare(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + return 0;
> +}
> +
> +static int lpass_cpu_mi2s_startup(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> +
> + lpaif_mi2s_osr_clk = clk_get(dai->dev, "mi2s_osr_clk");
> + if (IS_ERR(lpaif_mi2s_osr_clk)) {
> + dev_err(dai->dev, "%s: Error in getting mi2s_osr_clk\n",
> + __func__);
> + return PTR_ERR(lpaif_mi2s_osr_clk);
> + }
> +
> + lpaif_mi2s_bit_clk = clk_get(dai->dev, "mi2s_bit_clk");
> + if (IS_ERR(lpaif_mi2s_bit_clk)) {
> + dev_err(dai->dev, "%s: Error in getting mi2s_bit_clk\n",
> + __func__);
> + return PTR_ERR(lpaif_mi2s_bit_clk);
> + }
> +
> + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> + lpaif_cfg_i2s_playback(0, 0, LPAIF_MI2S);
> + } else {
> + dev_err(dai->dev, "%s: Invalid stream direction\n", __func__);
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static void lpass_cpu_mi2s_shutdown(struct snd_pcm_substream *substream,
> + struct snd_soc_dai *dai)
> +{
> + struct snd_pcm_runtime *runtime = substream->runtime;
> + struct lpass_runtime_data_t *prtd = runtime->private_data;
> +
> + if (prtd->lpaif_clk.is_osr_clk_enabled)
> + clk_disable_unprepare(lpaif_mi2s_osr_clk);
> + clk_put(lpaif_mi2s_osr_clk);
> +
> + if (prtd->lpaif_clk.is_bit_clk_enabled)
> + clk_disable_unprepare(lpaif_mi2s_bit_clk);
> + clk_put(lpaif_mi2s_bit_clk);
> +}
> +
> +static int lpass_cpu_mi2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
> +{
> + return 0;
> +}
> +
> +static struct snd_soc_dai_ops lpass_cpu_mi2s_ops = {
> + .startup = lpass_cpu_mi2s_startup,
> + .prepare = lpass_cpu_mi2s_prepare,
> + .hw_params = lpass_cpu_mi2s_hw_params,
> + .shutdown = lpass_cpu_mi2s_shutdown,
> + .set_fmt = lpass_cpu_mi2s_set_fmt,
> +};
> +
> +static struct snd_soc_dai_driver lpass_cpu_dais[] = {
> + {
> + .playback = {
> + .rates = SNDRV_PCM_RATE_8000_192000,
> + .formats = SNDRV_PCM_FMTBIT_S16 |
> + SNDRV_PCM_FMTBIT_S24 |
> + SNDRV_PCM_FMTBIT_S32,
> + .channels_min = 2,
> + .channels_max = 2,
> + .rate_min = 8000,
> + .rate_max = 192000,
> + },
> + .ops = &lpass_cpu_mi2s_ops,
> + .name = "lpass-mi2s-dai"
> + },
> +};
> +
> +static const struct snd_soc_component_driver lpass_cpu_component = {
> + .name = DRV_NAME,
> +};
> +
> +static int lpass_cpu_dai_probe(struct platform_device *pdev)
> +{
> + int ret;
> +
> + ret = snd_soc_register_component(&pdev->dev, &lpass_cpu_component,
> + lpass_cpu_dais, ARRAY_SIZE(lpass_cpu_dais));
> + if (ret)
> + dev_err(&pdev->dev, "%s: error registering soc dais\n",
> + __func__);
> +
> + return ret;
> +}
> +
> +static int lpass_cpu_dai_remove(struct platform_device *pdev)
> +{
> + snd_soc_unregister_component(&pdev->dev);
> + return 0;
> +}
> +
> +static const struct of_device_id lpass_cpu_dai_dt_match[] = {
> + {.compatible = "qcom,lpass-cpu-dai"},
> + {}
> +};
> +
> +static struct platform_driver lpass_cpu_dai_driver = {
> + .probe = lpass_cpu_dai_probe,
> + .remove = lpass_cpu_dai_remove,
> + .driver = {
> + .name = DRV_NAME,
> + .owner = THIS_MODULE,
> + .of_match_table = lpass_cpu_dai_dt_match,
> + },
> +};
> +module_platform_driver(lpass_cpu_dai_driver);
> +
> +MODULE_DESCRIPTION("QCOM LPASS CPU DAI DRIVER");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRV_NAME);
> +MODULE_DEVICE_TABLE(of, lpass_cpu_dai_dt_match);
> +MODULE_VERSION(DRV_VERSION);
>
next prev parent reply other threads:[~2014-11-19 21:18 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-19 18:52 [PATCH 0/9] ASoC: QCOM: Add support for ipq806x SOC Kenneth Westfield
2014-11-19 18:52 ` [PATCH 1/9] MAINTAINERS: Add QCOM audio ASoC maintainer Kenneth Westfield
2014-11-19 18:52 ` [PATCH 2/9] ASoC: qcom: Add device tree binding docs Kenneth Westfield
2014-11-25 21:26 ` Mark Brown
2014-11-19 18:52 ` [PATCH 3/9] ASoC: ipq806x: add native LPAIF driver Kenneth Westfield
2014-11-20 12:32 ` [alsa-devel] " Lars-Peter Clausen
2014-11-21 20:19 ` Kenneth Westfield
2014-11-25 21:44 ` Mark Brown
2014-11-19 18:52 ` [PATCH 4/9] ASoC: ipq806x: Add LPASS CPU DAI driver Kenneth Westfield
2014-11-19 21:17 ` Pierre-Louis Bossart [this message]
2014-11-21 20:23 ` [alsa-devel] " Kenneth Westfield
2014-11-20 0:20 ` Courtney Cavin
2014-11-20 12:36 ` [alsa-devel] " Lars-Peter Clausen
2014-11-25 21:53 ` Mark Brown
2014-11-19 18:52 ` [PATCH 5/9] ASoC: ipq806x: Add I2S PCM platform driver Kenneth Westfield
2014-11-19 21:10 ` [alsa-devel] " Pierre-Louis Bossart
2014-11-25 22:01 ` Mark Brown
2014-11-19 18:52 ` [PATCH 6/9] ASoC: ipq806x: Add machine driver for IPQ806X SOC Kenneth Westfield
2014-11-25 22:03 ` Mark Brown
2014-11-19 18:52 ` [PATCH 7/9] ASoC: qcom: Add ability to build QCOM drivers Kenneth Westfield
2014-11-25 22:07 ` Mark Brown
2014-11-27 1:26 ` Bryan Huntsman
2014-11-19 18:52 ` [PATCH 8/9] ASoC: Allow for building " Kenneth Westfield
2014-11-19 18:52 ` [PATCH 9/9] ARM: dts: Model IPQ LPASS audio hardware Kenneth Westfield
2014-11-19 22:54 ` Courtney Cavin
2014-11-21 20:17 ` [alsa-devel] " Kenneth Westfield
2014-11-25 22:08 ` Mark Brown
2014-11-19 20:16 ` [PATCH 0/9] ASoC: QCOM: Add support for ipq806x SOC Kumar Gala
2014-11-20 9:51 ` Mark Brown
2014-11-21 20:24 ` [alsa-devel] " Kenneth Westfield
2014-11-24 18:52 ` Mark Brown
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=546D08D2.5030808@linux.intel.com \
--to=pierre-louis.bossart@linux.intel.com \
--cc=alsa-devel@alsa-project.org \
--cc=bgoswami@codeaurora.org \
--cc=broonie@kernel.org \
--cc=bryanh@codeaurora.org \
--cc=davidb@codeaurora.org \
--cc=devicetree@vger.kernel.org \
--cc=gregkh@linuxfoundation.org \
--cc=kwestfie@codeaurora.org \
--cc=lgirdwood@gmail.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=plai@codeaurora.org \
--cc=rob.herring@calxeda.com \
--cc=tiwai@suse.de \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.