From patchwork Wed Feb 12 01:52:18 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Serbinski X-Patchwork-Id: 204916 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F1B22C3B187 for ; Wed, 12 Feb 2020 01:52:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B5F3F20848 for ; Wed, 12 Feb 2020 01:52:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=serbinski.com header.i=@serbinski.com header.b="VDpT2Fi1" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728144AbgBLBwv (ORCPT ); Tue, 11 Feb 2020 20:52:51 -0500 Received: from mail.serbinski.com ([162.218.126.2]:50324 "EHLO mail.serbinski.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728042AbgBLBwv (ORCPT ); Tue, 11 Feb 2020 20:52:51 -0500 Received: from localhost (unknown [127.0.0.1]) by mail.serbinski.com (Postfix) with ESMTP id 6FFC3D00693; Wed, 12 Feb 2020 01:52:49 +0000 (UTC) X-Virus-Scanned: amavisd-new at serbinski.com Received: from mail.serbinski.com ([127.0.0.1]) by localhost (mail.serbinski.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 6g8I74C66uh9; Tue, 11 Feb 2020 20:52:33 -0500 (EST) Received: from anet (23-233-80-73.cpe.pppoe.ca [23.233.80.73]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.serbinski.com (Postfix) with ESMTPSA id D861FD006F9; Tue, 11 Feb 2020 20:52:32 -0500 (EST) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.serbinski.com D861FD006F9 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=serbinski.com; s=default; t=1581472352; bh=5G+j9z85VmKhr+y6mqiRgd08if/sZtEwNi0yvFuTXBQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VDpT2Fi10Rzq62jJrNZd3Fec4fWBWHsRlojcCIDAEkoiw3WlrQFOGr3xzwkB/mNY2 6hT1AIt72Njgg1Pv5hEIuAe3GicGj4NKIjcy7PB84XUKREsonkSwvGJ2CqyXom3VDI oXiJ//yXQw77R3nkz0/eYsHAXU1SQfXOydZEePjc= From: Adam Serbinski To: Mark Brown , Srini Kandagatla , Rob Herring , Bjorn Andersson Cc: Adam Serbinski , Andy Gross , Mark Rutland , Liam Girdwood , Patrick Lai , Banajit Goswami , Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 2/6] ASoC: qdsp6: q6afe: add support to pcm ports Date: Tue, 11 Feb 2020 20:52:18 -0500 Message-Id: <20200212015222.8229-3-adam@serbinski.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200212015222.8229-1-adam@serbinski.com> References: <20200212015222.8229-1-adam@serbinski.com> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This patch adds support to pcm ports in AFE. Signed-off-by: Adam Serbinski CC: Andy Gross CC: Mark Rutland CC: Liam Girdwood CC: Patrick Lai CC: Banajit Goswami CC: Jaroslav Kysela CC: Takashi Iwai CC: alsa-devel@alsa-project.org CC: linux-arm-msm@vger.kernel.org CC: devicetree@vger.kernel.org CC: linux-kernel@vger.kernel.org --- sound/soc/qcom/qdsp6/q6afe.c | 118 +++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6afe.h | 13 +++- 2 files changed, 130 insertions(+), 1 deletion(-) diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index e0945f7a58c8..11de01679cad 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -40,6 +40,7 @@ #define AFE_PARAM_ID_SLIMBUS_CONFIG 0x00010212 #define AFE_PARAM_ID_I2S_CONFIG 0x0001020D +#define AFE_PARAM_ID_PCM_CONFIG 0x0001020E #define AFE_PARAM_ID_TDM_CONFIG 0x0001029D #define AFE_PARAM_ID_PORT_SLOT_MAPPING_CONFIG 0x00010297 @@ -117,6 +118,15 @@ #define AFE_PORT_ID_QUATERNARY_MI2S_RX 0x1006 #define AFE_PORT_ID_QUATERNARY_MI2S_TX 0x1007 +#define AFE_PORT_ID_PRIMARY_PCM_RX 0x100A +#define AFE_PORT_ID_PRIMARY_PCM_TX 0x100B +#define AFE_PORT_ID_SECONDARY_PCM_RX 0x100C +#define AFE_PORT_ID_SECONDARY_PCM_TX 0x100D +#define AFE_PORT_ID_TERTIARY_PCM_RX 0x1012 +#define AFE_PORT_ID_TERTIARY_PCM_TX 0x1013 +#define AFE_PORT_ID_QUATERNARY_PCM_RX 0x1014 +#define AFE_PORT_ID_QUATERNARY_PCM_TX 0x1015 + /* Start of the range of port IDs for TDM devices. */ #define AFE_PORT_ID_TDM_PORT_RANGE_START 0x9000 @@ -421,6 +431,29 @@ struct afe_digital_clk_cfg { u16 reserved; } __packed; +#define AFE_API_VERSION_PCM_CONFIG 0x1 +#define AFE_PORT_PCM_QUANT_MAX 0x5 +#define AFE_PORT_PCM_SYNC_SRC_EXTERNAL 0x0 +#define AFE_PORT_PCM_SYNC_SRC_INTERNAL 0x1 +#define AFE_PORT_PCM_AUX_MODE_PCM 0x0 +#define AFE_PORT_PCM_BITS_PER_FRAME_64 0x3 +#define AFE_PORT_PCM_BITS_PER_FRAME_128 0x4 +#define AFE_PORT_PCM_CTRL_DATA_OE_DISABLE 0x0 + +struct afe_param_id_pcm_cfg { + u32 pcm_cfg_minor_version; + u16 aux_mode; + u16 sync_src; + u16 frame_setting; + u16 quantype; + u16 ctrl_data_out_enable; + u16 reserved; + u32 sample_rate; + u16 bit_width; + u16 num_channels; + u16 slot_number_mapping[AFE_MAX_PCM_SLOT_COUNT]; +} __packed; + struct afe_param_id_i2s_cfg { u32 i2s_cfg_minor_version; u16 bit_width; @@ -452,6 +485,7 @@ union afe_port_config { struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch; struct afe_param_id_slimbus_cfg slim_cfg; struct afe_param_id_i2s_cfg i2s_cfg; + struct afe_param_id_pcm_cfg pcm_cfg; struct afe_param_id_tdm_cfg tdm_cfg; } __packed; @@ -707,6 +741,22 @@ static struct afe_port_map port_maps[AFE_PORT_MAX] = { QUINARY_TDM_TX_7, 0, 1}, [DISPLAY_PORT_RX] = { AFE_PORT_ID_HDMI_OVER_DP_RX, DISPLAY_PORT_RX, 1, 1}, + [PRIMARY_PCM_RX] = { AFE_PORT_ID_PRIMARY_PCM_RX, + PRIMARY_PCM_RX, 1, 1}, + [PRIMARY_PCM_TX] = { AFE_PORT_ID_PRIMARY_PCM_TX, + PRIMARY_PCM_RX, 0, 1}, + [SECONDARY_PCM_RX] = { AFE_PORT_ID_SECONDARY_PCM_RX, + SECONDARY_PCM_RX, 1, 1}, + [SECONDARY_PCM_TX] = { AFE_PORT_ID_SECONDARY_PCM_TX, + SECONDARY_PCM_TX, 0, 1}, + [TERTIARY_PCM_RX] = { AFE_PORT_ID_TERTIARY_PCM_RX, + TERTIARY_PCM_RX, 1, 1}, + [TERTIARY_PCM_TX] = { AFE_PORT_ID_TERTIARY_PCM_TX, + TERTIARY_PCM_TX, 0, 1}, + [QUATERNARY_PCM_RX] = { AFE_PORT_ID_QUATERNARY_PCM_RX, + QUATERNARY_PCM_RX, 1, 1}, + [QUATERNARY_PCM_TX] = { AFE_PORT_ID_QUATERNARY_PCM_TX, + QUATERNARY_PCM_TX, 0, 1}, }; static void q6afe_port_free(struct kref *ref) @@ -993,6 +1043,7 @@ int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id, break; case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR: case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1: + /* TDM cases overlap with PCM */ case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT: cset.clk_set_minor_version = AFE_API_VERSION_CLOCK_SET; cset.clk_id = clk_id; @@ -1145,6 +1196,63 @@ void q6afe_hdmi_port_prepare(struct q6afe_port *port, } EXPORT_SYMBOL_GPL(q6afe_hdmi_port_prepare); +/** + * q6afe_pcm_port_prepare() - Prepare pcm afe port. + * + * @port: Instance of afe port + * @cfg: PCM configuration for the afe port + * + */ +int q6afe_pcm_port_prepare(struct q6afe_port *port, struct q6afe_pcm_cfg *cfg) +{ + union afe_port_config *pcfg = &port->port_cfg; + struct device *dev = port->afe->dev; + + pcfg->pcm_cfg.pcm_cfg_minor_version = AFE_API_VERSION_PCM_CONFIG; + + if (cfg->quantype > AFE_PORT_PCM_QUANT_MAX) { + dev_err(dev, "Invalid pcm quantization\n"); + return -EINVAL; + } + pcfg->pcm_cfg.quantype = cfg->quantype; + + memcpy(pcfg->pcm_cfg.slot_number_mapping, cfg->slot_number_mapping, + sizeof(u16) * AFE_PORT_MAX_PCM_AUDIO_CHAN_CNT); + + pcfg->pcm_cfg.aux_mode = AFE_PORT_PCM_AUX_MODE_PCM; + switch (cfg->fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + pcfg->pcm_cfg.sync_src = AFE_PORT_PCM_SYNC_SRC_INTERNAL; + break; + case SND_SOC_DAIFMT_CBM_CFM: + pcfg->pcm_cfg.sync_src = AFE_PORT_PCM_SYNC_SRC_EXTERNAL; + break; + default: + dev_err(dev, "Unsupported format\n"); + return -EINVAL; + } + + switch (cfg->sample_rate) { + case 8000: + pcfg->pcm_cfg.frame_setting = AFE_PORT_PCM_BITS_PER_FRAME_128; + break; + case 16000: + pcfg->pcm_cfg.frame_setting = AFE_PORT_PCM_BITS_PER_FRAME_64; + break; + default: + dev_err(dev, "Unsupported sample rate\n"); + return -EINVAL; + } + pcfg->pcm_cfg.ctrl_data_out_enable = AFE_PORT_PCM_CTRL_DATA_OE_DISABLE; + pcfg->pcm_cfg.reserved = 0; + pcfg->pcm_cfg.sample_rate = cfg->sample_rate; + pcfg->pcm_cfg.bit_width = 16; + pcfg->pcm_cfg.num_channels = 1; + + return 0; +} +EXPORT_SYMBOL_GPL(q6afe_pcm_port_prepare); + /** * q6afe_i2s_port_prepare() - Prepare i2s afe port. * @@ -1417,6 +1525,16 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) case AFE_PORT_ID_QUATERNARY_MI2S_TX: cfg_type = AFE_PARAM_ID_I2S_CONFIG; break; + case AFE_PORT_ID_PRIMARY_PCM_RX: + case AFE_PORT_ID_PRIMARY_PCM_TX: + case AFE_PORT_ID_SECONDARY_PCM_RX: + case AFE_PORT_ID_SECONDARY_PCM_TX: + case AFE_PORT_ID_TERTIARY_PCM_RX: + case AFE_PORT_ID_TERTIARY_PCM_TX: + case AFE_PORT_ID_QUATERNARY_PCM_RX: + case AFE_PORT_ID_QUATERNARY_PCM_TX: + cfg_type = AFE_PARAM_ID_PCM_CONFIG; + break; case AFE_PORT_ID_PRIMARY_TDM_RX ... AFE_PORT_ID_QUINARY_TDM_TX_7: cfg_type = AFE_PARAM_ID_TDM_CONFIG; break; diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index c7ed5422baff..d3b79e391e44 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -5,7 +5,7 @@ #include -#define AFE_PORT_MAX 105 +#define AFE_PORT_MAX 113 #define MSM_AFE_PORT_TYPE_RX 0 #define MSM_AFE_PORT_TYPE_TX 1 @@ -14,7 +14,9 @@ #define Q6AFE_MAX_MI2S_LINES 4 #define AFE_MAX_CHAN_COUNT 8 +#define AFE_MAX_PCM_SLOT_COUNT 4 #define AFE_PORT_MAX_AUDIO_CHAN_CNT 0x8 +#define AFE_PORT_MAX_PCM_AUDIO_CHAN_CNT 0x4 #define Q6AFE_LPASS_CLK_SRC_INTERNAL 1 #define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0 @@ -170,6 +172,13 @@ struct q6afe_i2s_cfg { int fmt; }; +struct q6afe_pcm_cfg { + u16 quantype; + u32 sample_rate; + u16 slot_number_mapping[AFE_MAX_PCM_SLOT_COUNT]; + int fmt; +}; + struct q6afe_tdm_cfg { u16 num_channels; u32 sample_rate; @@ -188,6 +197,7 @@ struct q6afe_port_config { struct q6afe_hdmi_cfg hdmi; struct q6afe_slim_cfg slim; struct q6afe_i2s_cfg i2s_cfg; + struct q6afe_pcm_cfg pcm_cfg; struct q6afe_tdm_cfg tdm; }; @@ -203,6 +213,7 @@ void q6afe_hdmi_port_prepare(struct q6afe_port *port, void q6afe_slim_port_prepare(struct q6afe_port *port, struct q6afe_slim_cfg *cfg); int q6afe_i2s_port_prepare(struct q6afe_port *port, struct q6afe_i2s_cfg *cfg); +int q6afe_pcm_port_prepare(struct q6afe_port *port, struct q6afe_pcm_cfg *cfg); void q6afe_tdm_port_prepare(struct q6afe_port *port, struct q6afe_tdm_cfg *cfg); int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id, From patchwork Wed Feb 12 01:52:19 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Serbinski X-Patchwork-Id: 204914 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.9 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id A7B4CC35242 for ; Wed, 12 Feb 2020 01:53:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 6B2B720848 for ; Wed, 12 Feb 2020 01:53:24 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=serbinski.com header.i=@serbinski.com header.b="jXZThFMh" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727511AbgBLBxV (ORCPT ); Tue, 11 Feb 2020 20:53:21 -0500 Received: from mail.serbinski.com ([162.218.126.2]:50606 "EHLO mail.serbinski.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727414AbgBLBxU (ORCPT ); Tue, 11 Feb 2020 20:53:20 -0500 Received: from localhost (unknown [127.0.0.1]) by mail.serbinski.com (Postfix) with ESMTP id 679ABD00715; Wed, 12 Feb 2020 01:53:19 +0000 (UTC) X-Virus-Scanned: amavisd-new at serbinski.com Received: from mail.serbinski.com ([127.0.0.1]) by localhost (mail.serbinski.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 94Js4DC9Vdse; Tue, 11 Feb 2020 20:52:59 -0500 (EST) Received: from anet (23-233-80-73.cpe.pppoe.ca [23.233.80.73]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.serbinski.com (Postfix) with ESMTPSA id D3ABAD00716; Tue, 11 Feb 2020 20:52:37 -0500 (EST) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.serbinski.com D3ABAD00716 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=serbinski.com; s=default; t=1581472357; bh=sCqIaNBg22m4KSr5ybpHHBuJAkr81NYlbS+800oGfyI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jXZThFMhlIlcOd69D22R9GeDM6Zdi+0mmEoYsrFak4ZQKrgNZd2uMhSDxdwxYCnaH 1QnXRW+OsPX/cQdjo/nRuVOJ+PAf7fHGNmMUELhTSopbfD4hmb6nZvuKdQ7/Na/JT5 EBjnjBS6V8xX7Ld1Qmqqdc+1d3qq7MTK+lzmGTEE= From: Adam Serbinski To: Mark Brown , Srini Kandagatla , Rob Herring , Bjorn Andersson Cc: Adam Serbinski , Andy Gross , Mark Rutland , Liam Girdwood , Patrick Lai , Banajit Goswami , Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 3/6] ASoC: qdsp6: q6afe-dai: add support to pcm port dais Date: Tue, 11 Feb 2020 20:52:19 -0500 Message-Id: <20200212015222.8229-4-adam@serbinski.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200212015222.8229-1-adam@serbinski.com> References: <20200212015222.8229-1-adam@serbinski.com> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This patch adds support of AFE DAI for PCM port. Signed-off-by: Adam Serbinski CC: Andy Gross CC: Mark Rutland CC: Liam Girdwood CC: Patrick Lai CC: Banajit Goswami CC: Jaroslav Kysela CC: Takashi Iwai CC: alsa-devel@alsa-project.org CC: linux-arm-msm@vger.kernel.org CC: devicetree@vger.kernel.org CC: linux-kernel@vger.kernel.org --- sound/soc/qcom/qdsp6/q6afe-dai.c | 210 ++++++++++++++++++++++++++++++- 1 file changed, 205 insertions(+), 5 deletions(-) diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c index c1a7624eaf17..2deb8d6da462 100644 --- a/sound/soc/qcom/qdsp6/q6afe-dai.c +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -63,6 +63,8 @@ struct q6afe_dai_priv_data { uint32_t invert_sync; uint32_t data_delay; uint32_t data_align; + uint32_t quantype; + uint32_t slot_number_mapping[AFE_MAX_PCM_SLOT_COUNT]; }; struct q6afe_dai_data { @@ -151,6 +153,52 @@ static int q6hdmi_hw_params(struct snd_pcm_substream *substream, return 0; } +static int q6pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_pcm_cfg *pcm = &dai_data->port_config[dai->id].pcm_cfg; + int i = 0; + + switch (params_rate(params)) { + case 8000: + case 16000: + pcm->sample_rate = params_rate(params); + break; + default: + dev_err(dai->dev, "invalid sample rate = %u\n", + params_rate(params)); + return -EINVAL; + } + + pcm->quantype = dai_data->priv[dai->id].quantype; + + for (i = 0; i < AFE_MAX_PCM_SLOT_COUNT; i++) + pcm->slot_number_mapping[i] = + dai_data->priv[dai->id].slot_number_mapping[i]; + + return 0; +} + +static int q6pcm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_pcm_cfg *pcm = &dai_data->port_config[dai->id].pcm_cfg; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBM_CFM: + pcm->fmt = fmt; + break; + default: + dev_err(dai->dev, "unsupported format = %u\n", fmt); + return -EINVAL; + } + + return 0; +} + static int q6i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -358,6 +406,15 @@ static int q6afe_dai_prepare(struct snd_pcm_substream *substream, return rc; } break; + case PRIMARY_PCM_RX ... QUATERNARY_PCM_TX: + rc = q6afe_pcm_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].pcm_cfg); + if (rc < 0) { + dev_err(dai->dev, "fail to prepare AFE port %x\n", + dai->id); + return rc; + } + break; case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: q6afe_tdm_port_prepare(dai_data->port[dai->id], &dai_data->port_config[dai->id].tdm); @@ -429,16 +486,25 @@ static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai, Q6AFE_LPASS_CLK_ROOT_DEFAULT, freq, dir); case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR: + case Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT ... Q6AFE_LPASS_CLK_ID_QUI_PCM_OSR: + switch (dai->id) { + case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: + return q6afe_port_set_sysclk(port, clk_id, + Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + freq, dir); + break; + default: + return q6afe_port_set_sysclk(port, clk_id, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + freq, dir); + } case Q6AFE_LPASS_CLK_ID_MCLK_1 ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1: return q6afe_port_set_sysclk(port, clk_id, Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, Q6AFE_LPASS_CLK_ROOT_DEFAULT, freq, dir); - case Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT ... Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT: - return q6afe_port_set_sysclk(port, clk_id, - Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO, - Q6AFE_LPASS_CLK_ROOT_DEFAULT, - freq, dir); } return 0; @@ -468,6 +534,11 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"}, {"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"}, + {"Primary PCM Playback", NULL, "PRI_PCM_RX"}, + {"Secondary PCM Playback", NULL, "SEC_PCM_RX"}, + {"Tertiary PCM Playback", NULL, "TERT_PCM_RX"}, + {"Quaternary PCM Playback", NULL, "QUAT_PCM_RX"}, + {"Primary TDM0 Playback", NULL, "PRIMARY_TDM_RX_0"}, {"Primary TDM1 Playback", NULL, "PRIMARY_TDM_RX_1"}, {"Primary TDM2 Playback", NULL, "PRIMARY_TDM_RX_2"}, @@ -562,6 +633,11 @@ static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { {"PRI_MI2S_TX", NULL, "Primary MI2S Capture"}, {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"}, {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, + + {"PRI_PCM_TX", NULL, "Primary PCM Capture"}, + {"SEC_PCM_TX", NULL, "Secondary PCM Capture"}, + {"TERT_PCM_TX", NULL, "Tertiary PCM Capture"}, + {"QUAT_PCM_TX", NULL, "Quaternary PCM Capture"}, }; static const struct snd_soc_dai_ops q6hdmi_ops = { @@ -578,6 +654,14 @@ static const struct snd_soc_dai_ops q6i2s_ops = { .set_sysclk = q6afe_mi2s_set_sysclk, }; +static const struct snd_soc_dai_ops q6pcm_ops = { + .prepare = q6afe_dai_prepare, + .hw_params = q6pcm_hw_params, + .set_fmt = q6pcm_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + static const struct snd_soc_dai_ops q6slim_ops = { .prepare = q6afe_dai_prepare, .hw_params = q6slim_hw_params, @@ -1012,6 +1096,94 @@ static struct snd_soc_dai_driver q6afe_dais[] = { .ops = &q6i2s_ops, .probe = msm_dai_q6_dai_probe, .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Primary PCM Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .id = PRIMARY_PCM_RX, + .name = "PRI_PCM_RX", + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Primary PCM Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .id = PRIMARY_PCM_TX, + .name = "PRI_PCM_TX", + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Secondary PCM Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .name = "SEC_PCM_RX", + .id = SECONDARY_PCM_RX, + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Secondary PCM Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .id = SECONDARY_PCM_TX, + .name = "SEC_PCM_TX", + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Tertiary PCM Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .name = "TERT_PCM_RX", + .id = TERTIARY_PCM_RX, + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Tertiary PCM Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .id = TERTIARY_PCM_TX, + .name = "TERT_PCM_TX", + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Quaternary PCM Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .name = "QUAT_PCM_RX", + .id = QUATERNARY_PCM_RX, + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Quaternary PCM Capture", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .id = QUATERNARY_PCM_TX, + .name = "QUAT_PCM_TX", + .ops = &q6pcm_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, }, Q6AFE_TDM_PB_DAI("Primary", 0, PRIMARY_TDM_RX_0), Q6AFE_TDM_PB_DAI("Primary", 1, PRIMARY_TDM_RX_1), @@ -1169,6 +1341,15 @@ static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { SND_SOC_DAPM_AIF_OUT("PRI_MI2S_TX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("QUAT_PCM_RX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("QUAT_PCM_TX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("TERT_PCM_RX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("TERT_PCM_TX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SEC_PCM_RX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SEC_PCM_TX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("PRI_PCM_RX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("PRI_PCM_TX", NULL, 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_0", NULL, 0, 0, 0, 0), SND_SOC_DAPM_AIF_IN("PRIMARY_TDM_RX_1", NULL, @@ -1381,6 +1562,25 @@ static void of_q6afe_parse_dai_data(struct device *dev, for (i = 0; i < num_lines; i++) priv->sd_line_mask |= BIT(lines[i]); + break; + case PRIMARY_PCM_RX ... QUATERNARY_PCM_TX: + priv = &data->priv[id]; + ret = of_property_read_u32(node, "qcom,pcm-quantype", + &priv->quantype); + if (ret) { + dev_err(dev, "No quantype from DT\n"); + break; + } + + ret = of_property_read_variable_u32_array(node, + "qcom,pcm-slot-mapping", + priv->slot_number_mapping, + 1, AFE_MAX_PCM_SLOT_COUNT); + if (ret < 0) { + dev_err(dev, "No slot mapping from DT\n"); + break; + } + break; case PRIMARY_TDM_RX_0 ... QUINARY_TDM_TX_7: priv = &data->priv[id]; From patchwork Wed Feb 12 01:52:21 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Adam Serbinski X-Patchwork-Id: 204915 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.1 required=3.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B17F9C35242 for ; Wed, 12 Feb 2020 01:53:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 84D5A2082F for ; Wed, 12 Feb 2020 01:53:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (1024-bit key) header.d=serbinski.com header.i=@serbinski.com header.b="ENgRgVC+" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727556AbgBLBxF (ORCPT ); Tue, 11 Feb 2020 20:53:05 -0500 Received: from mail.serbinski.com ([162.218.126.2]:50462 "EHLO mail.serbinski.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727649AbgBLBxE (ORCPT ); Tue, 11 Feb 2020 20:53:04 -0500 Received: from localhost (unknown [127.0.0.1]) by mail.serbinski.com (Postfix) with ESMTP id 7FFABD00718; Wed, 12 Feb 2020 01:52:59 +0000 (UTC) X-Virus-Scanned: amavisd-new at serbinski.com Received: from mail.serbinski.com ([127.0.0.1]) by localhost (mail.serbinski.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ADjIgewZVsVa; Tue, 11 Feb 2020 20:52:49 -0500 (EST) Received: from anet (23-233-80-73.cpe.pppoe.ca [23.233.80.73]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.serbinski.com (Postfix) with ESMTPSA id 9E82FD00705; Tue, 11 Feb 2020 20:52:36 -0500 (EST) DKIM-Filter: OpenDKIM Filter v2.11.0 mail.serbinski.com 9E82FD00705 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=serbinski.com; s=default; t=1581472356; bh=qQ33OBoUwYvkzJ8dKPMjgyNVWI/zeHohTVgHOdxpxco=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ENgRgVC+FmWDhsOpbEqN640LOejfSnmnXlKi6Psf337AVVptsXrG9GPMxm67GOez9 fM1fSNMClO7eXwhDCHnmEvmDZ9iEI+fO7jzFmvZ4MMCzIwbfW/kPj8bGX8VpYp05hw pfDUvI6+CnTxKOZCFLzRpDvqREejM9s9MPqhywFQ= From: Adam Serbinski To: Mark Brown , Srini Kandagatla , Rob Herring , Bjorn Andersson Cc: Adam Serbinski , Andy Gross , Mark Rutland , Liam Girdwood , Patrick Lai , Banajit Goswami , Jaroslav Kysela , Takashi Iwai , alsa-devel@alsa-project.org, linux-arm-msm@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 5/6] ASoC: qcom: apq8096: add support for primary and quaternary I2S/PCM Date: Tue, 11 Feb 2020 20:52:21 -0500 Message-Id: <20200212015222.8229-6-adam@serbinski.com> X-Mailer: git-send-email 2.21.1 In-Reply-To: <20200212015222.8229-1-adam@serbinski.com> References: <20200212015222.8229-1-adam@serbinski.com> MIME-Version: 1.0 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This adds support to primary and quarternary I2S and PCM ports. Signed-off-by: Adam Serbinski CC: Andy Gross CC: Mark Rutland CC: Liam Girdwood CC: Patrick Lai CC: Banajit Goswami CC: Jaroslav Kysela CC: Takashi Iwai CC: alsa-devel@alsa-project.org CC: linux-arm-msm@vger.kernel.org CC: devicetree@vger.kernel.org CC: linux-kernel@vger.kernel.org --- sound/soc/qcom/apq8096.c | 86 +++++++++++++++++++++++++++++++++------- 1 file changed, 71 insertions(+), 15 deletions(-) diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c index 94363fd6846a..0dd58cdf34dd 100644 --- a/sound/soc/qcom/apq8096.c +++ b/sound/soc/qcom/apq8096.c @@ -8,24 +8,13 @@ #include #include #include "common.h" +#include "qdsp6/q6afe.h" #define SLIM_MAX_TX_PORTS 16 #define SLIM_MAX_RX_PORTS 16 #define WCD9335_DEFAULT_MCLK_RATE 9600000 - -static int apq8096_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_hw_params *params) -{ - struct snd_interval *rate = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_RATE); - struct snd_interval *channels = hw_param_interval(params, - SNDRV_PCM_HW_PARAM_CHANNELS); - - rate->min = rate->max = 48000; - channels->min = channels->max = 2; - - return 0; -} +#define MI2S_BCLK_RATE 1536000 +#define PCM_BCLK_RATE 1024000 static int msm_snd_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -33,10 +22,32 @@ static int msm_snd_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_interval *rate = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_RATE); + struct snd_interval *channels = hw_param_interval(params, + SNDRV_PCM_HW_PARAM_CHANNELS); u32 rx_ch[SLIM_MAX_RX_PORTS], tx_ch[SLIM_MAX_TX_PORTS]; u32 rx_ch_cnt = 0, tx_ch_cnt = 0; int ret = 0; + switch (cpu_dai->id) { + case PRIMARY_PCM_RX: + case PRIMARY_PCM_TX: + case QUATERNARY_PCM_RX: + case QUATERNARY_PCM_TX: + rate->min = 16000; + rate->max = 16000; + channels->min = 1; + channels->max = 1; + break; + default: + rate->min = 48000; + rate->max = 48000; + channels->min = 2; + channels->max = 2; + break; + } + ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch, &rx_ch_cnt, rx_ch); if (ret != 0 && ret != -ENOTSUPP) { @@ -60,8 +71,54 @@ static int msm_snd_hw_params(struct snd_pcm_substream *substream, return ret; } +static int msm_snd_startup(struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + switch (cpu_dai->id) { + case PRIMARY_MI2S_RX: + case PRIMARY_MI2S_TX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); + break; + case QUATERNARY_MI2S_RX: + case QUATERNARY_MI2S_TX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT, + MI2S_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); + break; + case PRIMARY_PCM_RX: + case PRIMARY_PCM_TX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT, + PCM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); + break; + case QUATERNARY_PCM_RX: + case QUATERNARY_PCM_TX: + snd_soc_dai_set_sysclk(cpu_dai, + Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT, + PCM_BCLK_RATE, SNDRV_PCM_STREAM_PLAYBACK); + snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_CBS_CFS); + snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_CBS_CFS); + break; + default: + return -1; + } + return 0; +} + static struct snd_soc_ops apq8096_ops = { .hw_params = msm_snd_hw_params, + .startup = msm_snd_startup, }; static int apq8096_init(struct snd_soc_pcm_runtime *rtd) @@ -96,7 +153,6 @@ static void apq8096_add_be_ops(struct snd_soc_card *card) for_each_card_prelinks(card, i, link) { if (link->no_pcm == 1) { - link->be_hw_params_fixup = apq8096_be_hw_params_fixup; link->init = apq8096_init; link->ops = &apq8096_ops; }