From patchwork Sat May 16 12:33:21 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 6421751 Return-Path: X-Original-To: patchwork-alsa-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 95BA2C0432 for ; Sat, 16 May 2015 12:38:57 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 69017205AA for ; Sat, 16 May 2015 12:38:56 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) by mail.kernel.org (Postfix) with ESMTP id 9F9A52056D for ; Sat, 16 May 2015 12:38:54 +0000 (UTC) Received: by alsa0.perex.cz (Postfix, from userid 1000) id A3E6526665A; Sat, 16 May 2015 14:38:53 +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, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from alsa0.perex.cz (localhost [IPv6:::1]) by alsa0.perex.cz (Postfix) with ESMTP id 253AF264EFF; Sat, 16 May 2015 14:34:53 +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 53AB1264EF3; Sat, 16 May 2015 14:34:52 +0200 (CEST) Received: from mail-wi0-f182.google.com (mail-wi0-f182.google.com [209.85.212.182]) by alsa0.perex.cz (Postfix) with ESMTP id 64C30264F38 for ; Sat, 16 May 2015 14:33:25 +0200 (CEST) Received: by wicmx19 with SMTP id mx19so57128305wic.0 for ; Sat, 16 May 2015 05:33:25 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RvCNAzlFG3Pcu6OIKT7P9vzbfcRyOd7l1FrK3uP2tkM=; b=SvLLoGysAbWoZ9UCJic1ptfi3Io7tIRMgbdW4y2M2JSqvjJz/5yE4d1p12/XtNpa8R Jw54Eq4jxHrwtztOLQB6rDOkT8tcqDpW+dCJJHGDPRPTNVrCJbeqm/HJAQxMfTnsYlB0 k3u5Gg0EZq+geNtZbQOpsEU+ERhGuz14uG+YSb0mtnFa6/nHfU3V0WgHPMIIEb897k0O U2xhD0xPTzZ0yd+tP6TjDsmlgOT7SS+prnHjGyzWDoNTFIraG6k4PpmFEgH0J2BdbBaq wmGfFyFuo0BHDhkSOWuXkAjLMuW4RorWucRQY0CI4IUXsY+V3GnVXYJinXK464RUWJqB vEZg== X-Gm-Message-State: ALoCoQkhZN+wHD4tC8w/JBTAz6qMvaMjwWdFsrZLDf/mifZ8ETvchnATq2r52RilXoLL8MHWHjPx X-Received: by 10.180.77.195 with SMTP id u3mr5842802wiw.30.1431779605220; Sat, 16 May 2015 05:33:25 -0700 (PDT) Received: from srini-ThinkPad-X1-Carbon-2nd.dlink.com (host-78-144-121-184.as13285.net. [78.144.121.184]) by mx.google.com with ESMTPSA id b10sm2745106wic.1.2015.05.16.05.33.23 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Sat, 16 May 2015 05:33:24 -0700 (PDT) From: Srinivas Kandagatla To: Patrick Lai , Mark Brown Date: Sat, 16 May 2015 13:33:21 +0100 Message-Id: <1431779601-2342-1-git-send-email-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1431779462-1732-1-git-send-email-srinivas.kandagatla@linaro.org> References: <1431779462-1732-1-git-send-email-srinivas.kandagatla@linaro.org> Cc: devicetree@vger.kernel.org, Kenneth Westfield , Banajit Goswami , Pawel Moll , Ian Campbell , Takashi Iwai , linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, Liam Girdwood , Rob Herring , Srinivas Kandagatla , Kumar Gala , alsa-devel@alsa-project.org Subject: [alsa-devel] [PATCH v2 10/13] ASoC: qcom: Add apq8016 lpass driver support 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: , MIME-Version: 1.0 Errors-To: alsa-devel-bounces@alsa-project.org Sender: alsa-devel-bounces@alsa-project.org X-Virus-Scanned: ClamAV using ClamSMTP This patch adds apq8016 lpass driver support. APQ8016 has 4 MI2S which can be routed to one internal codec and 2 external codec interfaces. Primary, Secondary, Quaternary I2S can do Rx(playback) and Tertiary and Quaternary can do Tx(capture). Tested-by: Kenneth Westfield Signed-off-by: Srinivas Kandagatla --- include/dt-bindings/sound/apq8016-lpass.h | 9 ++ sound/soc/qcom/Kconfig | 6 + sound/soc/qcom/Makefile | 2 + sound/soc/qcom/lpass-apq8016.c | 242 ++++++++++++++++++++++++++++++ sound/soc/qcom/lpass.h | 4 + 5 files changed, 263 insertions(+) create mode 100644 include/dt-bindings/sound/apq8016-lpass.h create mode 100644 sound/soc/qcom/lpass-apq8016.c diff --git a/include/dt-bindings/sound/apq8016-lpass.h b/include/dt-bindings/sound/apq8016-lpass.h new file mode 100644 index 0000000..499076e --- /dev/null +++ b/include/dt-bindings/sound/apq8016-lpass.h @@ -0,0 +1,9 @@ +#ifndef __DT_APQ8016_LPASS_H +#define __DT_APQ8016_LPASS_H + +#define MI2S_PRIMARY 0 +#define MI2S_SECONDARY 1 +#define MI2S_TERTIARY 2 +#define MI2S_QUATERNARY 3 + +#endif /* __DT_APQ8016_LPASS_H */ diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 865205e..9cc5ed7 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -20,6 +20,12 @@ config SND_SOC_LPASS_IPQ806X select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM +config SND_SOC_LPASS_APQ8016 + tristate + depends on SND_SOC_QCOM + select SND_SOC_LPASS_CPU + select SND_SOC_LPASS_PLATFORM + config SND_SOC_STORM tristate "ASoC I2S support for Storm boards" depends on (ARCH_QCOM && SND_SOC_QCOM) || COMPILE_TEST diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index f8aab91..ac76308 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -2,10 +2,12 @@ snd-soc-lpass-cpu-objs := lpass-cpu.o snd-soc-lpass-platform-objs := lpass-platform.o snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o +snd-soc-lpass-apq8016-objs := lpass-apq8016.o obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o +obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o # Machine snd-soc-storm-objs := storm.o diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c new file mode 100644 index 0000000..367fc46 --- /dev/null +++ b/sound/soc/qcom/lpass-apq8016.c @@ -0,0 +1,242 @@ +/* + * Copyright (c) 2010-2011,2013-2015 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. + * + * lpass-apq8016.c -- ALSA SoC CPU DAI driver for APQ8016 LPASS + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "lpass-lpaif-reg.h" +#include "lpass.h" + +static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = { + [MI2S_PRIMARY] = { + .id = MI2S_PRIMARY, + .name = "Primary MI2S", + .playback = { + .stream_name = "Primary Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 8, + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, + [MI2S_SECONDARY] = { + .id = MI2S_SECONDARY, + .name = "Secondary MI2S", + .playback = { + .stream_name = "Secondary Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 8, + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, + [MI2S_TERTIARY] = { + .id = MI2S_TERTIARY, + .name = "Tertiary MI2S", + .capture = { + .stream_name = "Tertiary Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 8, + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, + [MI2S_QUATERNARY] = { + .id = MI2S_QUATERNARY, + .name = "Quatenary MI2S", + .playback = { + .stream_name = "Quatenary Playback", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 8, + }, + .capture = { + .stream_name = "Quatenary Capture", + .formats = SNDRV_PCM_FMTBIT_S16 | + SNDRV_PCM_FMTBIT_S24 | + SNDRV_PCM_FMTBIT_S32, + .rates = SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000, + .rate_min = 8000, + .rate_max = 96000, + .channels_min = 1, + .channels_max = 8, + }, + .probe = &asoc_qcom_lpass_cpu_dai_probe, + .ops = &asoc_qcom_lpass_cpu_dai_ops, + }, +}; + +static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata) +{ + struct lpass_variant *v = drvdata->variant; + int chan = find_first_zero_bit(&drvdata->rdma_ch_bit_map, + v->rdma_channels); + + if (chan >= v->rdma_channels) + return -EBUSY; + + set_bit(chan, &drvdata->rdma_ch_bit_map); + + return chan; +} + +static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan) +{ + clear_bit(chan, &drvdata->rdma_ch_bit_map); + + return 0; +} + +static int apq8016_lpass_init(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int ret; + + drvdata->pcnoc_mport_clk = devm_clk_get(dev, "pcnoc-mport-clk"); + if (IS_ERR(drvdata->pcnoc_mport_clk)) { + dev_err(&pdev->dev, "%s() error getting pcnoc-mport-clk: %ld\n", + __func__, PTR_ERR(drvdata->pcnoc_mport_clk)); + return PTR_ERR(drvdata->pcnoc_mport_clk); + } + + ret = clk_prepare_enable(drvdata->pcnoc_mport_clk); + if (ret) { + dev_err(&pdev->dev, "%s() Error enabling pcnoc-mport-clk: %d\n", + __func__, ret); + return ret; + } + + drvdata->pcnoc_sway_clk = devm_clk_get(dev, "pcnoc-sway-clk"); + if (IS_ERR(drvdata->pcnoc_sway_clk)) { + dev_err(&pdev->dev, "%s() error getting pcnoc-sway-clk: %ld\n", + __func__, PTR_ERR(drvdata->pcnoc_sway_clk)); + return PTR_ERR(drvdata->pcnoc_sway_clk); + } + + ret = clk_prepare_enable(drvdata->pcnoc_sway_clk); + if (ret) { + dev_err(&pdev->dev, "%s() Error enabling pcnoc_sway_clk: %d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int apq8016_lpass_exit(struct platform_device *pdev) +{ + struct lpass_data *drvdata = platform_get_drvdata(pdev); + + clk_disable_unprepare(drvdata->pcnoc_mport_clk); + clk_disable_unprepare(drvdata->pcnoc_sway_clk); + + return 0; +} + + +struct lpass_variant apq8016_data = { + .i2sctrl_reg_base = 0x1000, + .i2sctrl_reg_stride = 0x1000, + .i2s_ports = 4, + .irq_reg_base = 0x6000, + .irq_reg_stride = 0x1000, + .irq_ports = 3, + .rdma_reg_base = 0x8400, + .rdma_reg_stride = 0x1000, + .rdma_channels = 2, + .rdmactl_audif_start = 1, + .dai_driver = apq8016_lpass_cpu_dai_driver, + .num_dai = ARRAY_SIZE(apq8016_lpass_cpu_dai_driver), + .init = apq8016_lpass_init, + .exit = apq8016_lpass_exit, + .alloc_dma_channel = apq8016_lpass_alloc_dma_channel, + .free_dma_channel = apq8016_lpass_free_dma_channel, +}; + +static const struct of_device_id apq8016_lpass_cpu_device_id[] = { + { .compatible = "qcom,lpass-cpu-apq8016", .data = &apq8016_data }, + {} +}; +MODULE_DEVICE_TABLE(of, apq8016_lpass_cpu_device_id); + +static struct platform_driver apq8016_lpass_cpu_platform_driver = { + .driver = { + .name = "apq8016-lpass-cpu", + .of_match_table = of_match_ptr(apq8016_lpass_cpu_device_id), + }, + .probe = asoc_qcom_lpass_cpu_platform_probe, + .remove = asoc_qcom_lpass_cpu_platform_remove, +}; +module_platform_driver(apq8016_lpass_cpu_platform_driver); + +MODULE_DESCRIPTION("APQ8016 LPASS CPU Driver"); +MODULE_LICENSE("GPL v2"); + diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index deecae9..d6e86c1 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -54,6 +54,10 @@ struct lpass_data { /* used it for handling interrupt per dma channel */ struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS]; + + /* 8016 specific */ + struct clk *pcnoc_mport_clk; + struct clk *pcnoc_sway_clk; }; /* Vairant data per each SOC */