From patchwork Fri May 18 12:55:59 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136302 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1205880lji; Fri, 18 May 2018 05:58:49 -0700 (PDT) X-Google-Smtp-Source: AB8JxZou1jFIDXGUMn+zj4iSaC3QSCEu9LYMYfzrUtZJTpsbs6sUjOmAbaYeLPp9pdpNezlO4oOn X-Received: by 2002:a17:902:3f81:: with SMTP id a1-v6mr9325436pld.29.1526648329629; Fri, 18 May 2018 05:58:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648329; cv=none; d=google.com; s=arc-20160816; b=IeRr6VGzeQM01iAz0Dtsz853cc1a2yGYT1EvYHrJQpMqpgVnt9XcAn1S7mWIumAOea /Egm/b3kjU6i0iohSXM5Y7xyaWJGSRUPszSrScuhwOrNCJUtyo49K95meHJ3zfO7r5nB JpYoOX9HPzE27tAQZZVy/Tfz656kvu6wjJPt8IM47o9b0kErJ1yl+F045kvsTJ9IJMfu zZc5gfT8c5Y1hIRkF0DnNgGKMEhOwAeW2IlwOPeZkx+Uw89Zk8dZLHK5yCqg3jILSf7s 6q/4mH1zanJNo3gij9n0lxBxwvJGyxIaGMpdGWqJVBymKA90Wx7Guku6D/lFGSy9IQ67 h59A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=meiYfaw8ctx1nnPt7KX7/XuDBFoORGPk+/jgdg0XHog=; b=WLnZl93GybIgGtnaUVL2lewWzY93NOpL53jU8r+4d0EMh1MV35I/05XVzN6SeIY6wD tSFhX5hCKuomdxi54M9mFQhusP1m4kTZkCdQ2vfKymicJzfOCSXTrGI3Xw98u9CG7Cwl jnUqFOMhSD/bJQOZzOqiuHCsahygi1C2n8Ce7VvPx++kr3Q/8s+f9yRNcsauwBBIq/95 oOQjatQjivcEH+E8S9cQSJgTgqV/Z2e7Bo0tlWmodMgOyKxw4ZSzXkdXS4cetYTg/Scc cjpIodEezVy+1SqUevJ1Y2u7mAYAFrD9IGZdUOHvZBYIcrIb2lvzLVRaApu/OzTySib4 /ipw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Da8mmp+w; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id x133-v6si7536191pfd.124.2018.05.18.05.58.49; Fri, 18 May 2018 05:58:49 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Da8mmp+w; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752160AbeERM6r (ORCPT + 13 others); Fri, 18 May 2018 08:58:47 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:32804 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752065AbeERM6m (ORCPT ); Fri, 18 May 2018 08:58:42 -0400 Received: by mail-wm0-f66.google.com with SMTP id x12-v6so3411709wmc.0 for ; Fri, 18 May 2018 05:58:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=mNdHQQgI0XF1WOaA5Ub43dGK1GSb/ICLaWtR7Rx38c4=; b=Da8mmp+wuOUWFy+SHs9FM6AAcpVx6LlCftAoz5GUy1B9hTANKyp7Bk0We/gUvnyBX2 AmWGlDZYRrGyxMjQY/2OyRlurl1rpIrDfNX1OmouZ7C3GYj/KTBFLv9DuCxgNk9phJyj /lgFozT4PdpL+k2Pa5EULU2Ifnp0xZHflAFmo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=mNdHQQgI0XF1WOaA5Ub43dGK1GSb/ICLaWtR7Rx38c4=; b=CYnROyA0NgtQBLfbfvs5sFgoe2/Nrttq4ltn7Uz7avTV6TsiEAe4kGxNC76JYcA3SR L3oK/46JEqyPw/6R/UK8TZfncd90OsofSMLxj58uCQeAmZegFqx761iElt59MspRsUw+ FLj+txcftcMTEz16jmW4lqZvlOtPkwmLaB4aY/uIGOkpmO7FbD+N6ngILHZcx3GCqake Ei0Y4r+98dIkyI4vz0qcTolD2BkQa6m98Vemxzj7/JqKGCh2F2zeRn0ZZla66yFkVHfP O91JKuzMiMnKCFEWTUWO9v2JckKbDOkUUzsOG9ypNHRQoGGBoSAdZXeBAJSvzdTi0i/3 ttcA== X-Gm-Message-State: ALKqPwfNsgdt0dRzOG3Qex2NHhEoDqEIw2CY6XzT5cXKb35PW5BlvDZM EtaJ8ME4x8d4vNPNzpxt8LYyrg== X-Received: by 2002:a1c:4701:: with SMTP id u1-v6mr4723226wma.42.1526648320684; Fri, 18 May 2018 05:58:40 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:40 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 04/15] ASoC: qdsp6: q6afe: Add support to MI2S sysclks Date: Fri, 18 May 2018 13:55:59 +0100 Message-Id: <20180518125610.26200-5-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch adds support to LPASS Bit clock, LPASS Digital core clock and OSR clock. These clocks are required for both MI2S and PCM setup. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/qdsp6/q6afe.c | 166 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6afe.h | 131 ++++++++++++++++++++++++++++++++++ 2 files changed, 297 insertions(+) -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index 0004369b3661..de0030068ecb 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -34,6 +34,9 @@ #define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG 0x00010235 +#define AFE_PARAM_ID_LPAIF_CLK_CONFIG 0x00010238 +#define AFE_PARAM_ID_INT_DIGITAL_CDC_CLK_CONFIG 0x00010239 + #define AFE_PARAM_ID_SLIMBUS_CONFIG 0x00010212 #define AFE_PARAM_ID_I2S_CONFIG 0x0001020D @@ -67,6 +70,11 @@ #define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E #define AFE_API_VERSION_SLIMBUS_CONFIG 0x1 +/* Clock set API version */ +#define AFE_API_VERSION_CLOCK_SET 1 +#define Q6AFE_LPASS_CLK_CONFIG_API_VERSION 0x1 +#define AFE_MODULE_CLOCK_SET 0x0001028F +#define AFE_PARAM_ID_CLOCK_SET 0x00010290 /* SLIMbus Rx port on channel 0. */ #define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX 0x4000 @@ -142,6 +150,13 @@ struct afe_port_param_data_v2 { u16 reserved; } __packed; +struct afe_svc_cmd_set_param { + uint32_t payload_size; + uint32_t payload_address_lsw; + uint32_t payload_address_msw; + uint32_t mem_map_handle; +} __packed; + struct afe_port_cmd_set_param_v2 { u16 port_id; u16 payload_size; @@ -202,6 +217,23 @@ struct afe_param_id_slimbus_cfg { */ } __packed; +struct afe_clk_cfg { + u32 i2s_cfg_minor_version; + u32 clk_val1; + u32 clk_val2; + u16 clk_src; + u16 clk_root; + u16 clk_set_mode; + u16 reserved; +} __packed; + +struct afe_digital_clk_cfg { + u32 i2s_cfg_minor_version; + u32 clk_val; + u16 clk_root; + u16 reserved; +} __packed; + struct afe_param_id_i2s_cfg { u32 i2s_cfg_minor_version; u16 bit_width; @@ -219,6 +251,16 @@ union afe_port_config { struct afe_param_id_i2s_cfg i2s_cfg; } __packed; + +struct afe_clk_set { + uint32_t clk_set_minor_version; + uint32_t clk_id; + uint32_t clk_freq_in_hz; + uint16_t clk_attri; + uint16_t clk_root; + uint32_t enable; +}; + struct q6afe_port { wait_queue_head_t wait; union afe_port_config port_cfg; @@ -404,6 +446,54 @@ static int afe_apr_send_pkt(struct q6afe *afe, struct apr_pkt *pkt, return ret; } +static int q6afe_port_set_param(struct q6afe_port *port, void *data, + int param_id, int module_id, int psize) +{ + struct afe_svc_cmd_set_param *param; + struct afe_port_param_data_v2 *pdata; + struct q6afe *afe = port->afe; + struct apr_pkt *pkt; + u16 port_id = port->id; + int ret, pkt_size; + void *p, *pl; + + pkt_size = APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata) + psize; + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + param = p + APR_HDR_SIZE; + pdata = p + APR_HDR_SIZE + sizeof(*param); + pl = p + APR_HDR_SIZE + sizeof(*param) + sizeof(*pdata); + memcpy(pl, data, psize); + + pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + pkt->hdr.pkt_size = pkt_size; + pkt->hdr.src_port = 0; + pkt->hdr.dest_port = 0; + pkt->hdr.token = port->token; + pkt->hdr.opcode = AFE_SVC_CMD_SET_PARAM; + + param->payload_size = sizeof(*pdata) + psize; + param->payload_address_lsw = 0x00; + param->payload_address_msw = 0x00; + param->mem_map_handle = 0x00; + pdata->module_id = module_id; + pdata->param_id = param_id; + pdata->param_size = psize; + + ret = afe_apr_send_pkt(afe, pkt, port); + if (ret) + dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n", + port_id, ret); + + kfree(pkt); + return ret; +} + static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data, int param_id, int module_id, int psize) { @@ -453,6 +543,82 @@ static int q6afe_port_set_param_v2(struct q6afe_port *port, void *data, return ret; } +static int q6afe_set_lpass_clock(struct q6afe_port *port, + struct afe_clk_cfg *cfg) +{ + return q6afe_port_set_param_v2(port, cfg, + AFE_PARAM_ID_LPAIF_CLK_CONFIG, + AFE_MODULE_AUDIO_DEV_INTERFACE, + sizeof(*cfg)); +} + +static int q6afe_set_lpass_clock_v2(struct q6afe_port *port, + struct afe_clk_set *cfg) +{ + return q6afe_port_set_param(port, cfg, AFE_PARAM_ID_CLOCK_SET, + AFE_MODULE_CLOCK_SET, sizeof(*cfg)); +} + +static int q6afe_set_digital_codec_core_clock(struct q6afe_port *port, + struct afe_digital_clk_cfg *cfg) +{ + return q6afe_port_set_param_v2(port, cfg, + AFE_PARAM_ID_INT_DIGITAL_CDC_CLK_CONFIG, + AFE_MODULE_AUDIO_DEV_INTERFACE, + sizeof(*cfg)); +} + +int q6afe_port_set_sysclk(struct q6afe_port *port, int clk_id, + int clk_src, int clk_root, + unsigned int freq, int dir) +{ + struct afe_clk_cfg ccfg = {0,}; + struct afe_clk_set cset = {0,}; + struct afe_digital_clk_cfg dcfg = {0,}; + int ret; + + switch (clk_id) { + case LPAIF_DIG_CLK: + dcfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG; + dcfg.clk_val = freq; + dcfg.clk_root = clk_root; + ret = q6afe_set_digital_codec_core_clock(port, &dcfg); + break; + case LPAIF_BIT_CLK: + ccfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG; + ccfg.clk_val1 = freq; + ccfg.clk_src = clk_src; + ccfg.clk_root = clk_root; + ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK1_VALID; + ret = q6afe_set_lpass_clock(port, &ccfg); + break; + + case LPAIF_OSR_CLK: + ccfg.i2s_cfg_minor_version = AFE_API_VERSION_I2S_CONFIG; + ccfg.clk_val2 = freq; + ccfg.clk_src = clk_src; + ccfg.clk_root = clk_root; + ccfg.clk_set_mode = Q6AFE_LPASS_MODE_CLK2_VALID; + ret = q6afe_set_lpass_clock(port, &ccfg); + break; + case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1: + cset.clk_set_minor_version = AFE_API_VERSION_CLOCK_SET; + cset.clk_id = clk_id; + cset.clk_freq_in_hz = freq; + cset.clk_attri = clk_src; + cset.clk_root = clk_root; + cset.enable = !!freq; + ret = q6afe_set_lpass_clock_v2(port, &cset); + break; + default: + ret = -EINVAL; + break; + } + + return ret; +} +EXPORT_SYMBOL_GPL(q6afe_port_set_sysclk); + /** * q6afe_port_stop() - Stop a afe port * diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 3cb3bb4985a9..5ca54a9bdfd5 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -16,6 +16,134 @@ #define AFE_MAX_CHAN_COUNT 8 #define AFE_PORT_MAX_AUDIO_CHAN_CNT 0x8 +#define Q6AFE_LPASS_CLK_SRC_INTERNAL 1 +#define Q6AFE_LPASS_CLK_ROOT_DEFAULT 0 + +#define LPAIF_DIG_CLK 1 +#define LPAIF_BIT_CLK 2 +#define LPAIF_OSR_CLK 3 + +/* Clock ID for Primary I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT 0x100 +/* Clock ID for Primary I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_PRI_MI2S_EBIT 0x101 +/* Clock ID for Secondary I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_IBIT 0x102 +/* Clock ID for Secondary I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_SEC_MI2S_EBIT 0x103 +/* Clock ID for Tertiary I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_TER_MI2S_IBIT 0x104 +/* Clock ID for Tertiary I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_TER_MI2S_EBIT 0x105 +/* Clock ID for Quartnery I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_IBIT 0x106 +/* Clock ID for Quartnery I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_QUAD_MI2S_EBIT 0x107 +/* Clock ID for Speaker I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_IBIT 0x108 +/* Clock ID for Speaker I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_EBIT 0x109 +/* Clock ID for Speaker I2S OSR */ +#define Q6AFE_LPASS_CLK_ID_SPEAKER_I2S_OSR 0x10A + +/* Clock ID for QUINARY I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_IBIT 0x10B +/* Clock ID for QUINARY I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_EBIT 0x10C +/* Clock ID for SENARY I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_IBIT 0x10D +/* Clock ID for SENARY I2S EBIT */ +#define Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT 0x10E +/* Clock ID for INT0 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT0_MI2S_IBIT 0x10F +/* Clock ID for INT1 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT1_MI2S_IBIT 0x110 +/* Clock ID for INT2 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT2_MI2S_IBIT 0x111 +/* Clock ID for INT3 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT3_MI2S_IBIT 0x112 +/* Clock ID for INT4 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT4_MI2S_IBIT 0x113 +/* Clock ID for INT5 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT5_MI2S_IBIT 0x114 +/* Clock ID for INT6 I2S IBIT */ +#define Q6AFE_LPASS_CLK_ID_INT6_MI2S_IBIT 0x115 + +/* Clock ID for QUINARY MI2S OSR CLK */ +#define Q6AFE_LPASS_CLK_ID_QUI_MI2S_OSR 0x116 + +/* Clock ID for Primary PCM IBIT */ +#define Q6AFE_LPASS_CLK_ID_PRI_PCM_IBIT 0x200 +/* Clock ID for Primary PCM EBIT */ +#define Q6AFE_LPASS_CLK_ID_PRI_PCM_EBIT 0x201 +/* Clock ID for Secondary PCM IBIT */ +#define Q6AFE_LPASS_CLK_ID_SEC_PCM_IBIT 0x202 +/* Clock ID for Secondary PCM EBIT */ +#define Q6AFE_LPASS_CLK_ID_SEC_PCM_EBIT 0x203 +/* Clock ID for Tertiary PCM IBIT */ +#define Q6AFE_LPASS_CLK_ID_TER_PCM_IBIT 0x204 +/* Clock ID for Tertiary PCM EBIT */ +#define Q6AFE_LPASS_CLK_ID_TER_PCM_EBIT 0x205 +/* Clock ID for Quartery PCM IBIT */ +#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_IBIT 0x206 +/* Clock ID for Quartery PCM EBIT */ +#define Q6AFE_LPASS_CLK_ID_QUAD_PCM_EBIT 0x207 +/* Clock ID for Quinary PCM IBIT */ +#define Q6AFE_LPASS_CLK_ID_QUIN_PCM_IBIT 0x208 +/* Clock ID for Quinary PCM EBIT */ +#define Q6AFE_LPASS_CLK_ID_QUIN_PCM_EBIT 0x209 +/* Clock ID for QUINARY PCM OSR */ +#define Q6AFE_LPASS_CLK_ID_QUI_PCM_OSR 0x20A + +/** Clock ID for Primary TDM IBIT */ +#define Q6AFE_LPASS_CLK_ID_PRI_TDM_IBIT 0x200 +/** Clock ID for Primary TDM EBIT */ +#define Q6AFE_LPASS_CLK_ID_PRI_TDM_EBIT 0x201 +/** Clock ID for Secondary TDM IBIT */ +#define Q6AFE_LPASS_CLK_ID_SEC_TDM_IBIT 0x202 +/** Clock ID for Secondary TDM EBIT */ +#define Q6AFE_LPASS_CLK_ID_SEC_TDM_EBIT 0x203 +/** Clock ID for Tertiary TDM IBIT */ +#define Q6AFE_LPASS_CLK_ID_TER_TDM_IBIT 0x204 +/** Clock ID for Tertiary TDM EBIT */ +#define Q6AFE_LPASS_CLK_ID_TER_TDM_EBIT 0x205 +/** Clock ID for Quartery TDM IBIT */ +#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_IBIT 0x206 +/** Clock ID for Quartery TDM EBIT */ +#define Q6AFE_LPASS_CLK_ID_QUAD_TDM_EBIT 0x207 +/** Clock ID for Quinary TDM IBIT */ +#define Q6AFE_LPASS_CLK_ID_QUIN_TDM_IBIT 0x208 +/** Clock ID for Quinary TDM EBIT */ +#define Q6AFE_LPASS_CLK_ID_QUIN_TDM_EBIT 0x209 +/** Clock ID for Quinary TDM OSR */ +#define Q6AFE_LPASS_CLK_ID_QUIN_TDM_OSR 0x20A + +/* Clock ID for MCLK1 */ +#define Q6AFE_LPASS_CLK_ID_MCLK_1 0x300 +/* Clock ID for MCLK2 */ +#define Q6AFE_LPASS_CLK_ID_MCLK_2 0x301 +/* Clock ID for MCLK3 */ +#define Q6AFE_LPASS_CLK_ID_MCLK_3 0x302 +/* Clock ID for MCLK4 */ +#define Q6AFE_LPASS_CLK_ID_MCLK_4 0x304 +/* Clock ID for Internal Digital Codec Core */ +#define Q6AFE_LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 0x303 +/* Clock ID for INT MCLK0 */ +#define Q6AFE_LPASS_CLK_ID_INT_MCLK_0 0x305 +/* Clock ID for INT MCLK1 */ +#define Q6AFE_LPASS_CLK_ID_INT_MCLK_1 0x306 + +/* Clock attribute for invalid use (reserved for internal usage) */ +#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVALID 0x0 +/* Clock attribute for no couple case */ +#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 +/* Clock attribute for dividend couple case */ +#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2 +/* Clock attribute for divisor couple case */ +#define Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3 +/* Clock attribute for invert and no couple case */ +#define Q6AFE_LPASS_CLK_ATTRIBUTE_INVERT_COUPLE_NO 0x4 + struct q6afe_hdmi_cfg { u16 datatype; u16 channel_allocation; @@ -59,4 +187,7 @@ 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_port_set_sysclk(struct q6afe_port *port, int clk_id, + int clk_src, int clk_root, + unsigned int freq, int dir); #endif /* __Q6AFE_H__ */ From patchwork Fri May 18 12:56:01 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136307 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1206133lji; Fri, 18 May 2018 05:59:06 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqungXsJnlU5viRaOi8QwYzlFAEna1ZZZUtBAUKTLZDqybQNHwVQljcJ3afzdr/4k5ddvBF X-Received: by 2002:a17:902:462:: with SMTP id 89-v6mr9334704ple.300.1526648346453; Fri, 18 May 2018 05:59:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648346; cv=none; d=google.com; s=arc-20160816; b=V4WupW2fPiQAUz8GiUp4MwcpJjMdtSDWvChtXyc0CB9qmxRPYyvi9bPbzo5+TKtDs4 QMzaUYwoSKgcPOzZH2zXW63S28YRKgl3JAuH7+vSbYXapM1aw6zTMRUwcob/AoEGV1Hs WPXb4WwYD3pJqJN7EzLOSH4fC1+qS5/UKxZ49L1nL5UKuy6sqdJdemb56nt/tbOrr6Gv 8s1TTv0jgGXrOunxKWwtdouCsOeqkj/5Xbf8PwDYrhpiP/b1ks0WlXqoludpaWGKsn1B YYrr/xgdzoZ6UBdoWXXCQW86SNHlwALSSL6KEkHLqwu6wqved8chA3o5tWxS7SeL2ZDx dSJw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=HyY+3F0b1xNP/poGhRJ6A0RnMP/5FY23nNDrC0z5s/o=; b=ia7xg/EAHM9PNw4VwFVoTNkzuAsneJD6+q0L2Y22/w/VnHxwoS/uRR5GVigQeV3CTT Euttm+NxLOLIbSu09TpiZ5oWspypuRa4z1eTlvVP1qhxCnV0wXsnav3+GhWfY2h6zswZ sqxRcYmFFVL+zHlcLZG0UoVOjjfTGZXp3XsiRnFw1klZZQnjHGmchKweJcUUj17vtdFn JsgjVCx8BO4ttljIWf3QCNIn6M0Xz4tsvfMl/iNtA1Bb/q3npypRZT15rGuTigx9JYpH t2m8+IfHA4AwG76RIQGNBV6PYHYHW0CrUBjdagB02rWnztI4hb+0ZsKWvXTPUJZqyxAM /ekQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=DppVBeL4; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m1-v6si6937599pls.70.2018.05.18.05.59.06; Fri, 18 May 2018 05:59:06 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=DppVBeL4; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751442AbeERM7C (ORCPT + 13 others); Fri, 18 May 2018 08:59:02 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:36997 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752103AbeERM6q (ORCPT ); Fri, 18 May 2018 08:58:46 -0400 Received: by mail-wm0-f66.google.com with SMTP id l1-v6so15052937wmb.2 for ; Fri, 18 May 2018 05:58:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=6HlBPomlAuVRvk3x5z8W5AzIqXxlYnmsFohInySHtWw=; b=DppVBeL4/455cWna6JD3sdDHTIjjWiMsR0r9XTwqbxB08A+2EL6ny5i0fI787XiH/B z8dI5pcsoksldCnRCVHCqcTY3R6EkSrOxgxqTtCGa1xba/V0r3fXXWqOuREA4d8Z8wlV W5z1DDOQwjabYcvQpq0k4KgQtMLIatCtjXvng= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=6HlBPomlAuVRvk3x5z8W5AzIqXxlYnmsFohInySHtWw=; b=Y6S99XvToG1eXnBlZHYPYIJFtrWMiPE3VAnHEqKJ1rke3vtl+W2EQHsnTMrxLiDMvx Fyd4EnAE6H+28N22fdWDezSDdL5aB3QuIhauKngYGFf5V7seIxDJdI9k8asDFAZR9+ox XCEMF558zXmK3/4aLHrXTvq3DYAL9jvr+R7ztOfYmzI2++VzlaAL4J7WQR4JalwqJa1m /0tQpxGhD2zGFgpUKMTPK+pW3oHYXjgHmx6UDeCKO6iKyl2vDkn41Is3ZcDWwT9cIOlx I0JOccg7PHSc5M2ZKrH+RMt+TnVl9KrgtFYv8pMa4ruPJRnXFwQ+bBA4o+7V4iJmKZjT qn4Q== X-Gm-Message-State: ALKqPwcEimzWGprLEGGx9uVArDkx/ojQnst4wksEkvV+GMDQxGAxk7t4 6fIfNRp14XS1y/6QXs1dggSo3A== X-Received: by 2002:a1c:8d90:: with SMTP id p138-v6mr4688565wmd.153.1526648323887; Fri, 18 May 2018 05:58:43 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:42 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 06/15] ASoC: qdsp6: q6asm: Add q6asm driver Date: Fri, 18 May 2018 13:56:01 +0100 Message-Id: <20180518125610.26200-7-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch adds basic support to Q6 ASM (Audio Stream Manager) module on Q6DSP. ASM supports up to 8 concurrent streams. each stream can be setup as playback/capture. ASM provides top control functions like Pause/flush/resume for playback and record. ASM can Create/destroy encoder, decoder and also provides POPP dynamic services. This patch adds support to basic features to allow hdmi playback. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6asm.c | 252 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6asm.h | 15 +++ 4 files changed, 272 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6asm.c create mode 100644 sound/soc/qcom/qdsp6/q6asm.h -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 971127edbc23..941774abd94f 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -53,6 +53,9 @@ config SND_SOC_QDSP6_AFE config SND_SOC_QDSP6_ADM tristate +config SND_SOC_QDSP6_ASM + tristate + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" depends on QCOM_APR && HAS_DMA @@ -60,6 +63,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE select SND_SOC_QDSP6_ADM + select SND_SOC_QDSP6_ASM help To add support for MSM QDSP6 Soc Audio. This will enable sound soc platform specific diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 95cdb3a12694..01d9dcf3375c 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o +obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c new file mode 100644 index 000000000000..585fcfbada6a --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -0,0 +1,252 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6asm.h" +#include "q6core.h" +#include "q6dsp-errno.h" +#include "q6dsp-common.h" + +#define ASM_SYNC_IO_MODE 0x0001 +#define ASM_ASYNC_IO_MODE 0x0002 +#define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ +#define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */ + +struct q6asm { + struct apr_device *adev; + struct device *dev; + struct q6core_svc_api_info ainfo; + wait_queue_head_t mem_wait; + struct platform_device *pcmdev; + spinlock_t slock; + struct audio_client *session[MAX_SESSIONS + 1]; + struct platform_device *pdev_dais; +}; + +struct audio_client { + int session; + q6asm_cb cb; + void *priv; + uint32_t io_mode; + struct apr_device *adev; + struct mutex cmd_lock; + spinlock_t lock; + struct kref refcount; + wait_queue_head_t cmd_wait; + struct aprv2_ibasic_rsp_result_t result; + int perf_mode; + int stream_id; + struct q6asm *q6asm; + struct device *dev; +}; + +static void q6asm_audio_client_release(struct kref *ref) +{ + struct audio_client *ac; + struct q6asm *a; + unsigned long flags; + + ac = container_of(ref, struct audio_client, refcount); + a = ac->q6asm; + + spin_lock_irqsave(&a->slock, flags); + a->session[ac->session] = NULL; + spin_unlock_irqrestore(&a->slock, flags); + + kfree(ac); +} + +/** + * q6asm_audio_client_free() - Freee allocated audio client + * + * @ac: audio client to free + */ +void q6asm_audio_client_free(struct audio_client *ac) +{ + kref_put(&ac->refcount, q6asm_audio_client_release); +} +EXPORT_SYMBOL_GPL(q6asm_audio_client_free); + +static struct audio_client *q6asm_get_audio_client(struct q6asm *a, + int session_id) +{ + struct audio_client *ac = NULL; + unsigned long flags; + + spin_lock_irqsave(&a->slock, flags); + if ((session_id <= 0) || (session_id > MAX_SESSIONS)) { + dev_err(a->dev, "invalid session: %d\n", session_id); + goto err; + } + + /* check for valid session */ + if (!a->session[session_id]) + goto err; + else if (a->session[session_id]->session != session_id) + goto err; + + ac = a->session[session_id]; + kref_get(&ac->refcount); +err: + spin_unlock_irqrestore(&a->slock, flags); + return ac; +} + +static int q6asm_srvc_callback(struct apr_device *adev, + struct apr_resp_pkt *data) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + struct audio_client *ac = NULL; + struct apr_hdr *hdr = &data->hdr; + uint32_t sid = 0; + + sid = (hdr->token >> 8) & 0x0F; + ac = q6asm_get_audio_client(q6asm, sid); + if (!ac) { + dev_err(&adev->dev, "Audio Client not active\n"); + return 0; + } + + if (ac->cb) + ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv); + + kref_put(&ac->refcount, q6asm_audio_client_release); + + return 0; +} + +/** + * q6asm_get_session_id() - get session id for audio client + * + * @c: audio client pointer + * + * Return: Will be an session id of the audio client. + */ +int q6asm_get_session_id(struct audio_client *c) +{ + return c->session; +} +EXPORT_SYMBOL_GPL(q6asm_get_session_id); + +/** + * q6asm_audio_client_alloc() - Allocate a new audio client + * + * @dev: Pointer to asm child device. + * @cb: event callback. + * @priv: private data associated with this client. + * @stream_id: stream id + * @perf_mode: performace mode for this client + * + * Return: Will be an error pointer on error or a valid audio client + * on success. + */ +struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, + void *priv, int stream_id, + int perf_mode) +{ + struct q6asm *a = dev_get_drvdata(dev->parent); + struct audio_client *ac; + unsigned long flags; + + ac = q6asm_get_audio_client(a, stream_id + 1); + if (ac) { + dev_err(dev, "Audio Client already active\n"); + return ac; + } + + ac = kzalloc(sizeof(*ac), GFP_KERNEL); + if (!ac) + return ERR_PTR(-ENOMEM); + + spin_lock_irqsave(&a->slock, flags); + a->session[stream_id + 1] = ac; + spin_unlock_irqrestore(&a->slock, flags); + ac->session = stream_id + 1; + ac->cb = cb; + ac->dev = dev; + ac->q6asm = a; + ac->priv = priv; + ac->io_mode = ASM_SYNC_IO_MODE; + ac->perf_mode = perf_mode; + /* DSP expects stream id from 1 */ + ac->stream_id = 1; + ac->adev = a->adev; + kref_init(&ac->refcount); + + init_waitqueue_head(&ac->cmd_wait); + mutex_init(&ac->cmd_lock); + spin_lock_init(&ac->lock); + + return ac; +} +EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); + + +static int q6asm_probe(struct apr_device *adev) +{ + struct device *dev = &adev->dev; + struct device_node *dais_np; + struct q6asm *q6asm; + + q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL); + if (!q6asm) + return -ENOMEM; + + q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo); + + q6asm->dev = dev; + q6asm->adev = adev; + init_waitqueue_head(&q6asm->mem_wait); + spin_lock_init(&q6asm->slock); + dev_set_drvdata(dev, q6asm); + + dais_np = of_get_child_by_name(dev->of_node, "dais"); + if (dais_np) { + q6asm->pdev_dais = of_platform_device_create(dais_np, + "q6asm-dai", dev); + of_node_put(dais_np); + } + + return 0; +} + +static int q6asm_remove(struct apr_device *adev) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + + if (q6asm->pdev_dais) + of_platform_device_destroy(&q6asm->pdev_dais->dev, NULL); + + return 0; +} +static const struct of_device_id q6asm_device_id[] = { + { .compatible = "qcom,q6asm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, q6asm_device_id); + +static struct apr_driver qcom_q6asm_driver = { + .probe = q6asm_probe, + .remove = q6asm_remove, + .callback = q6asm_srvc_callback, + .driver = { + .name = "qcom-q6asm", + .of_match_table = of_match_ptr(q6asm_device_id), + }, +}; + +module_apr_driver(qcom_q6asm_driver); +MODULE_DESCRIPTION("Q6 Audio Stream Manager driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h new file mode 100644 index 000000000000..b7816e6384e7 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6_ASM_H__ +#define __Q6_ASM_H__ + +#define MAX_SESSIONS 8 + +typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token, + void *payload, void *priv); +struct audio_client; +struct audio_client *q6asm_audio_client_alloc(struct device *dev, + q6asm_cb cb, void *priv, + int session_id, int perf_mode); +void q6asm_audio_client_free(struct audio_client *ac); +int q6asm_get_session_id(struct audio_client *ac); +#endif /* __Q6_ASM_H__ */ From patchwork Fri May 18 12:56:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136313 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1206596lji; Fri, 18 May 2018 05:59:28 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpUvqsw4b792wrJCQxMvzGwj5f9LbuuqaILlx/wJ82rJH7dqiumGmsy/nrFjBa23knfq5jD X-Received: by 2002:a63:3408:: with SMTP id b8-v6mr5067451pga.258.1526648368812; Fri, 18 May 2018 05:59:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648368; cv=none; d=google.com; s=arc-20160816; b=TTuZw+5Q6+WIkMqP5sqPZLtYZXWnWk9t/jdZ569cByBVj2WeFboF3XZuDZqO5aDPVG 9fpcxvi7/y/YnyOVznItSA/8WS0xFGvCzS/DB5iA0GBfEcgU3M6uN2Ra+mgDVTmgkRrj lT3cGVuUTeOoNnjsaPMTrPLnm5j722ZI7pWbhizh+J4L+sZLuUHA82EJxlblzmWsUDAb 8WFFi//1lFh/MEJI/uCIyl+MMhqFSfINf8olbdCXtYsOmGl+QclwGGL5gpIFBRpac/ez R4/XUa8hBF0n8p0dE/wuFHLacMFb9AIfIT0taXxpA9Mdj8H9lEsnNw47cA2EHNk1WFXI fhRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=BQI3DHF7e0OOWZODHetfF3mLiO8NjBRidenFgrYsCiU=; b=PaFFlewA97ZaKu1s+4mGV3d7K9Of1ZAnadr8Qp3Y/ORqBg9JmUYmjKOMNaOovj7A/6 cl113joiKpMwYzLKG6HS/U2umIi0mn9e5ticvejhYYHfXtwTLtXrwJ+5v1vOu0yiTgln 4+rvzjW+h1ga6BUZlKlUwxkflUKGti7MbBkwxMf61V+1MUOuPxnIlu/RewN6Z0heLFpi n2r8EQqmoX7Npzb019nbNnVMNXjjCV/V0aThnjMfmfIHQGKxmEw0OtnIGs7cjlfog2Xw RcWNoTLbRxXQoQrkMtA6uT9zrZ7QkQ9rqSteF3kGYNTgBpo6uEbRx/ica6zqgEtD/oKI B5cA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=MbiTbpbg; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h12-v6si7604169pfd.253.2018.05.18.05.59.28; Fri, 18 May 2018 05:59:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=MbiTbpbg; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752024AbeERM7Y (ORCPT + 13 others); Fri, 18 May 2018 08:59:24 -0400 Received: from mail-wr0-f193.google.com ([209.85.128.193]:46792 "EHLO mail-wr0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752065AbeERM6s (ORCPT ); Fri, 18 May 2018 08:58:48 -0400 Received: by mail-wr0-f193.google.com with SMTP id x9-v6so6255654wrl.13 for ; Fri, 18 May 2018 05:58:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=WBNgcej44DjEEIR/k1G53+UcjUmOuP/vkXPSyDTAFio=; b=MbiTbpbgK+ZvVNVGsh+ZAwnjr5cWL8W13CySXRg3RYdQPrNpKuZWd4mqsFLVxqhBQI +auBIZNnCmMURxEDY+wZy61Oaa6wshvPyhGH4yYOLWLtaLaNxBVTChmuBo2BzLqWk6GP HOXNxnqJs/PX0gG7sW8F1LdopEOqfQDTIPLbo= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=WBNgcej44DjEEIR/k1G53+UcjUmOuP/vkXPSyDTAFio=; b=gj1le6AzaPPLmW5urRs8xB7fk/Ukxgs0ooRfMZ9dIXck6Bu8R8dEdzjOHL8nA6FS1Y IgG+idTdfwwhORKy3uO4xOfNjuv/d9DCLfPYnGuCJHONbw48dfBJttK0AnNnZyGYMOjc nJCdHInO6HizzmPs31gzC+NLh12/s+YeDHM7iwwhf4E8bluDLSw83akTbF0eGnLviPog 4mDMS05Yrb1n8Q9mdysOAVEBfh6UrKHqBrtszPWuzNgFlQWKPSNdQhCLNq90pVnpY7YJ Lesyodz/g8uT2UwoQ5dioSUfQAcwKpPhgCHRDRvfsnJUxXX1VYQsLC0DxSy+vD1DaCqJ n+hg== X-Gm-Message-State: ALKqPwfhwFom7m71FvVbm+SoeCJV0yWEMliNwYHOxy4+DR8CLzsisZz9 EVyMoeTq6Uao1i67cyBKcohklA== X-Received: by 2002:adf:c328:: with SMTP id n37-v6mr7954573wrf.91.1526648326666; Fri, 18 May 2018 05:58:46 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.45 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:46 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 08/15] ASoC: qdsp6: q6asm: Add support to audio stream apis Date: Fri, 18 May 2018 13:56:03 +0100 Message-Id: <20180518125610.26200-9-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch adds support to open, write and media format commands in the q6asm module. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/qdsp6/q6asm.c | 802 ++++++++++++++++++++++++++++++++++++++++++- sound/soc/qcom/qdsp6/q6asm.h | 49 +++ 2 files changed, 850 insertions(+), 1 deletion(-) -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index a20d243ed10a..530852385cad 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -19,10 +21,36 @@ #include "q6dsp-errno.h" #include "q6dsp-common.h" +#define ASM_STREAM_CMD_CLOSE 0x00010BCD +#define ASM_STREAM_CMD_FLUSH 0x00010BCE +#define ASM_SESSION_CMD_PAUSE 0x00010BD3 +#define ASM_DATA_CMD_EOS 0x00010BDB +#define ASM_NULL_POPP_TOPOLOGY 0x00010C68 +#define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09 +#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10 +#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68 #define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94 - +#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98 +#define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99 +#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3 +#define ASM_SESSION_CMD_RUN_V2 0x00010DAA +#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 +#define ASM_DATA_CMD_WRITE_V2 0x00010DAB +#define ASM_DATA_CMD_READ_V2 0x00010DAC +#define ASM_SESSION_CMD_SUSPEND 0x00010DEC +#define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3 +#define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4 +#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A +#define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D + + +#define ASM_LEGACY_STREAM_SESSION 0 +/* Bit shift for the stream_perf_mode subfield. */ +#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29 +#define ASM_END_POINT_DEVICE_MATRIX 0 +#define ASM_DEFAULT_APP_TYPE 0 #define ASM_SYNC_IO_MODE 0x0001 #define ASM_ASYNC_IO_MODE 0x0002 #define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ @@ -46,6 +74,89 @@ struct avs_cmd_shared_mem_unmap_regions { u32 mem_map_handle; } __packed; +struct asm_data_cmd_media_fmt_update_v2 { + u32 fmt_blk_size; +} __packed; + +struct asm_multi_channel_pcm_fmt_blk_v2 { + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + u16 num_channels; + u16 bits_per_sample; + u32 sample_rate; + u16 is_signed; + u16 reserved; + u8 channel_mapping[PCM_MAX_NUM_CHANNEL]; +} __packed; + +struct asm_stream_cmd_set_encdec_param { + u32 param_id; + u32 param_size; +} __packed; + +struct asm_enc_cfg_blk_param_v2 { + u32 frames_per_buf; + u32 enc_cfg_blk_size; +} __packed; + +struct asm_multi_channel_pcm_enc_cfg_v2 { + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + uint16_t num_channels; + uint16_t bits_per_sample; + uint32_t sample_rate; + uint16_t is_signed; + uint16_t reserved; + uint8_t channel_mapping[8]; +} __packed; + +struct asm_data_cmd_read_v2 { + u32 buf_addr_lsw; + u32 buf_addr_msw; + u32 mem_map_handle; + u32 buf_size; + u32 seq_id; +} __packed; + +struct asm_data_cmd_read_v2_done { + u32 status; + u32 buf_addr_lsw; + u32 buf_addr_msw; +}; + +struct asm_stream_cmd_open_read_v3 { + u32 mode_flags; + u32 src_endpointype; + u32 preprocopo_id; + u32 enc_cfg_id; + u16 bits_per_sample; + u16 reserved; +} __packed; + +struct asm_data_cmd_write_v2 { + u32 buf_addr_lsw; + u32 buf_addr_msw; + u32 mem_map_handle; + u32 buf_size; + u32 seq_id; + u32 timestamp_lsw; + u32 timestamp_msw; + u32 flags; +} __packed; + +struct asm_stream_cmd_open_write_v3 { + uint32_t mode_flags; + uint16_t sink_endpointype; + uint16_t bits_per_sample; + uint32_t postprocopo_id; + uint32_t dec_fmt_id; +} __packed; + +struct asm_session_cmd_run_v2 { + u32 flags; + u32 time_lsw; + u32 time_msw; +} __packed; + struct audio_buffer { phys_addr_t phys; uint32_t size; /* size of buffer */ @@ -409,6 +520,149 @@ static struct audio_client *q6asm_get_audio_client(struct q6asm *a, return ac; } +static int32_t q6asm_stream_callback(struct apr_device *adev, + struct apr_resp_pkt *data, + int session_id) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + struct aprv2_ibasic_rsp_result_t *result; + struct apr_hdr *hdr = &data->hdr; + struct audio_port_data *port; + struct audio_client *ac; + uint32_t client_event = 0; + int ret = 0; + + ac = q6asm_get_audio_client(q6asm, session_id); + if (!ac)/* Audio client might already be freed by now */ + return 0; + + result = data->payload; + + switch (hdr->opcode) { + case APR_BASIC_RSP_RESULT: + switch (result->opcode) { + case ASM_SESSION_CMD_PAUSE: + client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE; + break; + case ASM_SESSION_CMD_SUSPEND: + client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE; + break; + case ASM_DATA_CMD_EOS: + client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE; + break; + case ASM_STREAM_CMD_FLUSH: + client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE; + break; + case ASM_SESSION_CMD_RUN_V2: + client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE; + break; + case ASM_STREAM_CMD_CLOSE: + client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE; + break; + case ASM_STREAM_CMD_FLUSH_READBUFS: + client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE; + break; + case ASM_STREAM_CMD_OPEN_WRITE_V3: + case ASM_STREAM_CMD_OPEN_READ_V3: + case ASM_STREAM_CMD_OPEN_READWRITE_V2: + case ASM_STREAM_CMD_SET_ENCDEC_PARAM: + case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: + if (result->status != 0) { + dev_err(ac->dev, + "cmd = 0x%x returned error = 0x%x\n", + result->opcode, result->status); + ac->result = *result; + wake_up(&ac->cmd_wait); + ret = 0; + goto done; + } + break; + default: + dev_err(ac->dev, "command[0x%x] not expecting rsp\n", + result->opcode); + break; + } + + ac->result = *result; + wake_up(&ac->cmd_wait); + + if (ac->cb) + ac->cb(client_event, hdr->token, + data->payload, ac->priv); + + ret = 0; + goto done; + + case ASM_DATA_EVENT_WRITE_DONE_V2: + client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE; + if (ac->io_mode & ASM_SYNC_IO_MODE) { + phys_addr_t phys; + unsigned long flags; + + spin_lock_irqsave(&ac->lock, flags); + + port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; + + if (!port->buf) { + spin_unlock_irqrestore(&ac->lock, flags); + ret = 0; + goto done; + } + + phys = port->buf[hdr->token].phys; + + if (lower_32_bits(phys) != result->opcode || + upper_32_bits(phys) != result->status) { + dev_err(ac->dev, "Expected addr %pa\n", + &port->buf[hdr->token].phys); + spin_unlock_irqrestore(&ac->lock, flags); + ret = -EINVAL; + goto done; + } + spin_unlock_irqrestore(&ac->lock, flags); + } + break; + case ASM_DATA_EVENT_READ_DONE_V2: + client_event = ASM_CLIENT_EVENT_DATA_READ_DONE; + if (ac->io_mode & ASM_SYNC_IO_MODE) { + struct asm_data_cmd_read_v2_done *done = data->payload; + unsigned long flags; + phys_addr_t phys; + + spin_lock_irqsave(&ac->lock, flags); + port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; + if (!port->buf) { + spin_unlock_irqrestore(&ac->lock, flags); + ret = 0; + goto done; + } + + phys = port->buf[hdr->token].phys; + + if (upper_32_bits(phys) != done->buf_addr_msw || + lower_32_bits(phys) != done->buf_addr_lsw) { + dev_err(ac->dev, "Expected addr %pa %08x-%08x\n", + &port->buf[hdr->token].phys, + done->buf_addr_lsw, + done->buf_addr_msw); + spin_unlock_irqrestore(&ac->lock, flags); + ret = -EINVAL; + goto done; + } + spin_unlock_irqrestore(&ac->lock, flags); + } + + break; + } + + if (ac->cb) + ac->cb(client_event, hdr->token, data->payload, ac->priv); + +done: + kref_put(&ac->refcount, q6asm_audio_client_release); + return ret; +} + static int q6asm_srvc_callback(struct apr_device *adev, struct apr_resp_pkt *data) { @@ -420,6 +674,11 @@ static int q6asm_srvc_callback(struct apr_device *adev, struct q6asm *a; uint32_t sid = 0; uint32_t dir = 0; + int session_id; + + session_id = (hdr->dest_port >> 8) & 0xFF; + if (session_id) + return q6asm_stream_callback(adev, data, session_id); sid = (hdr->token >> 8) & 0x0F; ac = q6asm_get_audio_client(q6asm, sid); @@ -540,6 +799,547 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, } EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); +static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt) +{ + struct apr_hdr *hdr = &pkt->hdr; + int rc; + + mutex_lock(&ac->cmd_lock); + ac->result.opcode = 0; + ac->result.status = 0; + + rc = apr_send_pkt(ac->adev, pkt); + if (rc < 0) + goto err; + + rc = wait_event_timeout(ac->cmd_wait, + (ac->result.opcode == hdr->opcode), 5 * HZ); + if (!rc) { + dev_err(ac->dev, "CMD timeout\n"); + rc = -ETIMEDOUT; + goto err; + } + + if (ac->result.status > 0) { + dev_err(ac->dev, "DSP returned error[%x]\n", + ac->result.status); + rc = -EINVAL; + } else { + rc = 0; + } + + +err: + mutex_unlock(&ac->cmd_lock); + return rc; +} + +/** + * q6asm_open_write() - Open audio client for writing + * + * @ac: audio client pointer + * @format: audio sample format + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_open_write(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + struct asm_stream_cmd_open_write_v3 *open; + struct apr_pkt *pkt; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*open); + + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + open = p + APR_HDR_SIZE; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3; + open->mode_flags = 0x00; + open->mode_flags |= ASM_LEGACY_STREAM_SESSION; + + /* source endpoint : matrix */ + open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX; + open->bits_per_sample = bits_per_sample; + open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; + + switch (format) { + case FORMAT_LINEAR_PCM: + open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; + default: + dev_err(ac->dev, "Invalid format 0x%x\n", format); + rc = -EINVAL; + goto err; + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + if (rc < 0) + goto err; + + ac->io_mode |= ASM_TUN_WRITE_IO_MODE; + +err: + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_open_write); + +static int __q6asm_run(struct audio_client *ac, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts, bool wait) +{ + struct asm_session_cmd_run_v2 *run; + struct apr_pkt *pkt; + int pkt_size, rc; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*run); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + run = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2; + run->flags = flags; + run->time_lsw = lsw_ts; + run->time_msw = msw_ts; + if (wait) { + rc = q6asm_ac_send_cmd_sync(ac, pkt); + } else { + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + } + + kfree(pkt); + return rc; +} + +/** + * q6asm_run() - start the audio client + * + * @ac: audio client pointer + * @flags: flags associated with write + * @msw_ts: timestamp msw + * @lsw_ts: timestamp lsw + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_run(struct audio_client *ac, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts) +{ + return __q6asm_run(ac, flags, msw_ts, lsw_ts, true); +} +EXPORT_SYMBOL_GPL(q6asm_run); + +/** + * q6asm_run_nowait() - start the audio client withou blocking + * + * @ac: audio client pointer + * @flags: flags associated with write + * @msw_ts: timestamp msw + * @lsw_ts: timestamp lsw + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts) +{ + return __q6asm_run(ac, flags, msw_ts, lsw_ts, false); +} +EXPORT_SYMBOL_GPL(q6asm_run_nowait); + +/** + * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration + * + * @ac: audio client pointer + * @rate: audio sample rate + * @channels: number of audio channels. + * @channel_map: channel map pointer + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, + uint32_t rate, uint32_t channels, + u8 channel_map[PCM_MAX_NUM_CHANNEL], + uint16_t bits_per_sample) +{ + struct asm_multi_channel_pcm_fmt_blk_v2 *fmt; + struct apr_pkt *pkt; + u8 *channel_mapping; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*fmt); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + fmt = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); + fmt->num_channels = channels; + fmt->bits_per_sample = bits_per_sample; + fmt->sample_rate = rate; + fmt->is_signed = 1; + + channel_mapping = fmt->channel_mapping; + + if (channel_map) { + memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL); + } else { + if (q6dsp_map_channels(channel_mapping, channels)) { + dev_err(ac->dev, " map channels failed %d\n", channels); + rc = -EINVAL; + goto err; + } + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + +err: + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); + +/** + * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture + * + * @ac: audio client pointer + * @rate: audio sample rate + * @channels: number of audio channels. + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, + uint32_t rate, uint32_t channels, uint16_t bits_per_sample) +{ + struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg; + struct apr_pkt *pkt; + u8 *channel_mapping; + u32 frames_per_buf = 0; + int pkt_size, rc; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + enc_cfg = p + APR_HDR_SIZE; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; + enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec); + enc_cfg->encblk.frames_per_buf = frames_per_buf; + enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size - + sizeof(struct asm_enc_cfg_blk_param_v2); + + enc_cfg->num_channels = channels; + enc_cfg->bits_per_sample = bits_per_sample; + enc_cfg->sample_rate = rate; + enc_cfg->is_signed = 1; + channel_mapping = enc_cfg->channel_mapping; + + if (q6dsp_map_channels(channel_mapping, channels)) { + rc = -EINVAL; + goto err; + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); +err: + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); + +/** + * q6asm_read() - read data of period size from audio client + * + * @ac: audio client pointer + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_read(struct audio_client *ac) +{ + struct asm_data_cmd_read_v2 *read; + struct audio_port_data *port; + struct audio_buffer *ab; + struct apr_pkt *pkt; + unsigned long flags; + int pkt_size; + int rc = 0; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*read); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + read = p + APR_HDR_SIZE; + + spin_lock_irqsave(&ac->lock, flags); + port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); + ab = &port->buf[port->dsp_buf]; + pkt->hdr.opcode = ASM_DATA_CMD_READ_V2; + read->buf_addr_lsw = lower_32_bits(ab->phys); + read->buf_addr_msw = upper_32_bits(ab->phys); + read->mem_map_handle = port->mem_map_handle; + + read->buf_size = ab->size; + read->seq_id = port->dsp_buf; + pkt->hdr.token = port->dsp_buf; + + port->dsp_buf++; + + if (port->dsp_buf >= port->num_periods) + port->dsp_buf = 0; + + spin_unlock_irqrestore(&ac->lock, flags); + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + else + pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc); + + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_read); + +static int __q6asm_open_read(struct audio_client *ac, + uint32_t format, uint16_t bits_per_sample) +{ + struct asm_stream_cmd_open_read_v3 *open; + struct apr_pkt *pkt; + int pkt_size, rc; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*open); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + open = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3; + /* Stream prio : High, provide meta info with encoded frames */ + open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX; + + open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE; + open->bits_per_sample = bits_per_sample; + open->mode_flags = 0x0; + + open->mode_flags |= ASM_LEGACY_STREAM_SESSION << + ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ; + + switch (format) { + case FORMAT_LINEAR_PCM: + open->mode_flags |= 0x00; + open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; + default: + pr_err("Invalid format[%d]\n", format); + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + + kfree(pkt); + return rc; +} + +/** + * q6asm_open_read() - Open audio client for reading + * + * @ac: audio client pointer + * @format: audio sample format + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_open_read(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_read(ac, format, bits_per_sample); +} +EXPORT_SYMBOL_GPL(q6asm_open_read); + +/** + * q6asm_write_async() - non blocking write + * + * @ac: audio client pointer + * @len: lenght in bytes + * @msw_ts: timestamp msw + * @lsw_ts: timestamp lsw + * @wflags: flags associated with write + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, + uint32_t lsw_ts, uint32_t wflags) +{ + struct asm_data_cmd_write_v2 *write; + struct audio_port_data *port; + struct audio_buffer *ab; + unsigned long flags; + struct apr_pkt *pkt; + int pkt_size; + int rc = 0; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*write); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + write = p + APR_HDR_SIZE; + + spin_lock_irqsave(&ac->lock, flags); + port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); + + ab = &port->buf[port->dsp_buf]; + pkt->hdr.token = port->dsp_buf; + pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2; + write->buf_addr_lsw = lower_32_bits(ab->phys); + write->buf_addr_msw = upper_32_bits(ab->phys); + write->buf_size = len; + write->seq_id = port->dsp_buf; + write->timestamp_lsw = lsw_ts; + write->timestamp_msw = msw_ts; + write->mem_map_handle = + ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle; + + if (wflags == NO_TIMESTAMP) + write->flags = (wflags & 0x800000FF); + else + write->flags = (0x80000000 | wflags); + + port->dsp_buf++; + + if (port->dsp_buf >= port->num_periods) + port->dsp_buf = 0; + + spin_unlock_irqrestore(&ac->lock, flags); + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_write_async); + +static void q6asm_reset_buf_state(struct audio_client *ac) +{ + struct audio_port_data *port = NULL; + unsigned long flags; + + spin_lock_irqsave(&ac->lock, flags); + port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; + port->dsp_buf = 0; + port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; + port->dsp_buf = 0; + spin_unlock_irqrestore(&ac->lock, flags); +} + +static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait) +{ + int stream_id = ac->stream_id; + struct apr_pkt pkt; + int rc; + + q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id); + + switch (cmd) { + case CMD_PAUSE: + pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE; + break; + case CMD_SUSPEND: + pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND; + break; + case CMD_FLUSH: + pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH; + break; + case CMD_OUT_FLUSH: + pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS; + break; + case CMD_EOS: + pkt.hdr.opcode = ASM_DATA_CMD_EOS; + break; + case CMD_CLOSE: + pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE; + break; + default: + return -EINVAL; + } + + if (wait) + rc = q6asm_ac_send_cmd_sync(ac, &pkt); + else + return apr_send_pkt(ac->adev, &pkt); + + if (rc < 0) + return rc; + + if (cmd == CMD_FLUSH) + q6asm_reset_buf_state(ac); + + return 0; +} + +/** + * q6asm_cmd() - run cmd on audio client + * + * @ac: audio client pointer + * @cmd: command to run on audio client. + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_cmd(struct audio_client *ac, int cmd) +{ + return __q6asm_cmd(ac, cmd, true); +} +EXPORT_SYMBOL_GPL(q6asm_cmd); + +/** + * q6asm_cmd_nowait() - non blocking, run cmd on audio client + * + * @ac: audio client pointer + * @cmd: command to run on audio client. + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_cmd_nowait(struct audio_client *ac, int cmd) +{ + return __q6asm_cmd(ac, cmd, false); +} +EXPORT_SYMBOL_GPL(q6asm_cmd_nowait); static int q6asm_probe(struct apr_device *adev) { diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 8c317b7b63c3..9f5fb573e4a0 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -1,8 +1,36 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __Q6_ASM_H__ #define __Q6_ASM_H__ +#include "q6dsp-common.h" +#include + +/* ASM client callback events */ +#define CMD_PAUSE 0x0001 +#define ASM_CLIENT_EVENT_CMD_PAUSE_DONE 0x1001 +#define CMD_FLUSH 0x0002 +#define ASM_CLIENT_EVENT_CMD_FLUSH_DONE 0x1002 +#define CMD_EOS 0x0003 +#define ASM_CLIENT_EVENT_CMD_EOS_DONE 0x1003 +#define CMD_CLOSE 0x0004 +#define ASM_CLIENT_EVENT_CMD_CLOSE_DONE 0x1004 +#define CMD_OUT_FLUSH 0x0005 +#define ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE 0x1005 +#define CMD_SUSPEND 0x0006 +#define ASM_CLIENT_EVENT_CMD_SUSPEND_DONE 0x1006 +#define ASM_CLIENT_EVENT_CMD_RUN_DONE 0x1008 +#define ASM_CLIENT_EVENT_DATA_WRITE_DONE 0x1009 +#define ASM_CLIENT_EVENT_DATA_READ_DONE 0x100a + +enum { + LEGACY_PCM_MODE = 0, + LOW_LATENCY_PCM_MODE, + ULTRA_LOW_LATENCY_PCM_MODE, + ULL_POST_PROCESSING_PCM_MODE, +}; #define MAX_SESSIONS 8 +#define NO_TIMESTAMP 0xFF00 +#define FORMAT_LINEAR_PCM 0x0000 typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token, void *payload, void *priv); @@ -11,6 +39,27 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, void *priv, int session_id, int perf_mode); void q6asm_audio_client_free(struct audio_client *ac); +int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, + uint32_t lsw_ts, uint32_t flags); +int q6asm_open_write(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + +int q6asm_open_read(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); +int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, + uint32_t rate, uint32_t channels, uint16_t bits_per_sample); +int q6asm_read(struct audio_client *ac); + +int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, + uint32_t rate, uint32_t channels, + u8 channel_map[PCM_MAX_NUM_CHANNEL], + uint16_t bits_per_sample); +int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, + uint32_t lsw_ts); +int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, + uint32_t lsw_ts); +int q6asm_cmd(struct audio_client *ac, int cmd); +int q6asm_cmd_nowait(struct audio_client *ac, int cmd); int q6asm_get_session_id(struct audio_client *ac); int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, From patchwork Fri May 18 12:56:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136312 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1206569lji; Fri, 18 May 2018 05:59:26 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpfI8WTJ3dvsdGbAyFkbTOY3nPi9NC93ubSPwkGlK8CG8PE9stl245lIVcSnverwspfmNWD X-Received: by 2002:a17:902:9004:: with SMTP id a4-v6mr9343431plp.143.1526648366838; Fri, 18 May 2018 05:59:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648366; cv=none; d=google.com; s=arc-20160816; b=y2x+vOF3JnfUjIvvbLompNUNuJ9RKHcyc8Cc9yOivp71Za/W1Z3pcjrzxmnC2OME6N ezseH5qqCi5HKk/PpPIkL9uAd5KC6fhUMvVxQbrnjZIuufPbPvwKVszquWy9hnT2mz+H NirZU2hkrk/u+lCGETd4HWJTO+ziRHatVp0KKoJpaHQomAiH0ere807HV8LBYZkyq4xu s19fS/nfjHBqdFMrxrb3geinkhBcvZCxBe8LnXA87AozCUXaxcdASi9KN56ZSvO7dCEr c5XWoulfyXprWF+edRg6oxDnFVtqN3UT2mGM3t5qpMcelQWw9LtvaGh6/sQ18+8oBbx7 fp3A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=j/J+rSNBeoS1MjxQx74C9Z4cT+fG+ak2bojVh2RhFlo=; b=IOMjIlH9FKFMaLdJsY8p4b1P+4ECKQiAdPYq+E9VmsSSIqAoLn7ffa1Uc6UY4WDN/y /VVymgcWvGITqBL6v3vziUSPYweuuUvWECAyvqzqUbdYla/f4piqYNBPoOIMrTfPLqZF LH3Fq33FMtjPhqIhdJisDoxDBSGdpW85YqwTWaYXePmDTwzw0qRFTsLVxFkWtDNJ+6vh q0qTvWxXkmU8Z9hLuWuWSjm8JmbtL42fE1miJBkmBskVNU/xHYVAO+m0i7r6YYcFO1ch znngbWWcuEaMaBrTzuN+jBBI91dXCL0/TgqLzNLiXctF2nYi1JNucd5DqHaIpJJDnjjn wreQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Lumwvt4q; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id h12-v6si7604169pfd.253.2018.05.18.05.59.26; Fri, 18 May 2018 05:59:26 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Lumwvt4q; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752384AbeERM7W (ORCPT + 13 others); Fri, 18 May 2018 08:59:22 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:45764 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752199AbeERM6t (ORCPT ); Fri, 18 May 2018 08:58:49 -0400 Received: by mail-wr0-f195.google.com with SMTP id w3-v6so1417324wrl.12 for ; Fri, 18 May 2018 05:58:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=9RPOa4y1036sFP+Nm3lhbS0G87EmGsZL8N0P20JbMnI=; b=Lumwvt4qkm/hgkYswde68opwU8YxGLvs9Pp6hAymThh+e+K6Flsh/aPbEybBZ4zZXt UJJ1czLTPUoT6IkcZjin4XwE+G4qG9hfVXFu2fcQ9KwzjwZ3yn1FxbDGSs4H7fRMjpiU /jB9U9bRhj7QTQ73LdMpaibx4oY7v/c4x3BEs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=9RPOa4y1036sFP+Nm3lhbS0G87EmGsZL8N0P20JbMnI=; b=KDbtU0qI9kMYO9pEc9YzHuid9XZ02dB5M+DrT14IKBUNB+CtBFwZ4F1mWj7C9R9aDh xdpCrktSfcXIbiSkdry7RCJyD7KfZevRSr4IOTmVbEH90vJEdakj0liIqZqsQxiTACZc Cjug/7fvenlae5qCbtxZvUu3qxpMyzunMfAxGbXt3a1sPn8gZYOgvAnMNZpX64glsvgZ UkXxFSN1wY3azAwIObIZ++LafHqFQF3M9tftzlq0jY/izIMW7D8jMZ7TzwybjlrSkV/k QzWpcIvoJHHCtQV5CNBx4Zef3qlfVf9vY0gCBE3pKEz7QOC5eGpLkVwe97wxDuwjUd1u YGxg== X-Gm-Message-State: ALKqPwcoklGm+NcxcMPQ9YYBkI5SLWwFd3gw7hCAh0Kw6TDcqAyH+BuQ j0R5QPAh93umUIeDT6ph+MKuHw== X-Received: by 2002:adf:eb8f:: with SMTP id t15-v6mr3649891wrn.243.1526648328035; Fri, 18 May 2018 05:58:48 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:47 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 09/15] ASoC: qdsp6: q6routing: Add q6routing driver Date: Fri, 18 May 2018 13:56:04 +0100 Message-Id: <20180518125610.26200-10-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch adds support to q6 routing driver which configures route between ASM and AFE module using ADM apis. This driver uses dapm widgets to setup the matrix between AFE ports and ASM streams. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6routing.c | 400 +++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6routing.h | 9 + 4 files changed, 414 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6routing.c create mode 100644 sound/soc/qcom/qdsp6/q6routing.h -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 941774abd94f..43f9ed85efa8 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -53,6 +53,9 @@ config SND_SOC_QDSP6_AFE config SND_SOC_QDSP6_ADM tristate +config SND_SOC_QDSP6_ROUTING + tristate + config SND_SOC_QDSP6_ASM tristate @@ -63,6 +66,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE select SND_SOC_QDSP6_ADM + select SND_SOC_QDSP6_ROUTING select SND_SOC_QDSP6_ASM help To add support for MSM QDSP6 Soc Audio. diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 01d9dcf3375c..0e8e2febb7ec 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o +obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c new file mode 100644 index 000000000000..1d7a4088a435 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -0,0 +1,400 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6afe.h" +#include "q6asm.h" +#include "q6adm.h" +#include "q6routing.h" + +#define DRV_NAME "q6routing-component" + +struct session_data { + int state; + int port_id; + int path_type; + int app_type; + int acdb_id; + int sample_rate; + int bits_per_sample; + int channels; + int perf_mode; + int numcopps; + int fedai_id; + unsigned long copp_map; + struct q6copp *copps[MAX_COPPS_PER_PORT]; +}; + +struct msm_routing_data { + struct session_data sessions[MAX_SESSIONS]; + struct session_data port_data[AFE_MAX_PORTS]; + struct device *dev; + struct mutex lock; +}; + +static struct msm_routing_data *routing_data; + +/** + * q6routing_stream_open() - Register a new stream for route setup + * + * @fedai_id: Frontend dai id. + * @perf_mode: Performance mode. + * @stream_id: ASM stream id to map. + * @stream_type: Direction of stream + * + * Return: Will be an negative on error or a zero on success. + */ +int q6routing_stream_open(int fedai_id, int perf_mode, + int stream_id, int stream_type) +{ + int j, topology, num_copps = 0; + struct route_payload payload; + struct q6copp *copp; + int copp_idx; + struct session_data *session, *pdata; + + if (!routing_data) { + pr_err("Routing driver not yet ready\n"); + return -EINVAL; + } + + session = &routing_data->sessions[stream_id - 1]; + pdata = &routing_data->port_data[session->port_id]; + + mutex_lock(&routing_data->lock); + session->fedai_id = fedai_id; + + session->path_type = pdata->path_type; + session->sample_rate = pdata->sample_rate; + session->channels = pdata->channels; + session->bits_per_sample = pdata->bits_per_sample; + + payload.num_copps = 0; /* only RX needs to use payload */ + topology = NULL_COPP_TOPOLOGY; + copp = q6adm_open(routing_data->dev, session->port_id, + session->path_type, session->sample_rate, + session->channels, topology, perf_mode, + session->bits_per_sample, 0, 0); + + if (!copp) { + mutex_unlock(&routing_data->lock); + return -EINVAL; + } + + copp_idx = q6adm_get_copp_id(copp); + set_bit(copp_idx, &session->copp_map); + session->copps[copp_idx] = copp; + + for_each_set_bit(j, &session->copp_map, MAX_COPPS_PER_PORT) { + payload.port_id[num_copps] = session->port_id; + payload.copp_idx[num_copps] = j; + num_copps++; + } + + if (num_copps) { + payload.num_copps = num_copps; + payload.session_id = stream_id; + q6adm_matrix_map(routing_data->dev, session->path_type, + payload, perf_mode); + } + mutex_unlock(&routing_data->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(q6routing_stream_open); + +static struct session_data *get_session_from_id(struct msm_routing_data *data, + int fedai_id) +{ + int i; + + for (i = 0; i < MAX_SESSIONS; i++) { + if (fedai_id == data->sessions[i].fedai_id) + return &data->sessions[i]; + } + + return NULL; +} +/** + * q6routing_stream_close() - Deregister a stream + * + * @fedai_id: Frontend dai id. + * @stream_type: Direction of stream + * + * Return: Will be an negative on error or a zero on success. + */ +void q6routing_stream_close(int fedai_id, int stream_type) +{ + struct session_data *session; + int idx; + + session = get_session_from_id(routing_data, fedai_id); + if (!session) + return; + + for_each_set_bit(idx, &session->copp_map, MAX_COPPS_PER_PORT) { + if (session->copps[idx]) { + q6adm_close(routing_data->dev, session->copps[idx]); + session->copps[idx] = NULL; + } + } + + session->fedai_id = -1; + session->copp_map = 0; +} +EXPORT_SYMBOL_GPL(q6routing_stream_close); + +static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int session_id = mc->shift; + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct msm_routing_data *priv = dev_get_drvdata(c->dev); + struct session_data *session = &priv->sessions[session_id]; + + if (session->port_id == mc->reg) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct msm_routing_data *data = dev_get_drvdata(c->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + int be_id = mc->reg; + int session_id = mc->shift; + struct session_data *session = &data->sessions[session_id]; + + if (ucontrol->value.integer.value[0]) { + session->port_id = be_id; + snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update); + } else { + session->port_id = -1; + snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update); + } + + return 1; +} + +static const struct snd_kcontrol_new hdmi_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { + /* Frontend AIF */ + SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), + + /* Mixer definitions */ + SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0, + hdmi_mixer_controls, + ARRAY_SIZE(hdmi_mixer_controls)), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"HDMI Mixer", "MultiMedia1", "MM_DL1"}, + {"HDMI Mixer", "MultiMedia2", "MM_DL2"}, + {"HDMI Mixer", "MultiMedia3", "MM_DL3"}, + {"HDMI Mixer", "MultiMedia4", "MM_DL4"}, + {"HDMI Mixer", "MultiMedia5", "MM_DL5"}, + {"HDMI Mixer", "MultiMedia6", "MM_DL6"}, + {"HDMI Mixer", "MultiMedia7", "MM_DL7"}, + {"HDMI Mixer", "MultiMedia8", "MM_DL8"}, + {"HDMI_RX", NULL, "HDMI Mixer"}, +}; + +static int routing_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct msm_routing_data *data = dev_get_drvdata(c->dev); + unsigned int be_id = rtd->cpu_dai->id; + struct session_data *session; + int path_type; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + path_type = ADM_PATH_PLAYBACK; + else + path_type = ADM_PATH_LIVE_REC; + + if (be_id > AFE_MAX_PORTS) + return -EINVAL; + + session = &data->port_data[be_id]; + + mutex_lock(&data->lock); + + session->path_type = path_type; + session->sample_rate = params_rate(params); + session->channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + session->bits_per_sample = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + session->bits_per_sample = 24; + break; + default: + break; + } + + mutex_unlock(&data->lock); + return 0; +} + +static struct snd_pcm_ops q6pcm_routing_ops = { + .hw_params = routing_hw_params, +}; + +static int msm_routing_probe(struct snd_soc_component *c) +{ + int i; + + for (i = 0; i < MAX_SESSIONS; i++) + routing_data->sessions[i].port_id = -1; + + return 0; +} + +static const struct snd_soc_component_driver msm_soc_routing_component = { + .ops = &q6pcm_routing_ops, + .probe = msm_routing_probe, + .name = DRV_NAME, + .dapm_widgets = msm_qdsp6_widgets, + .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), +}; + +static int q6routing_dai_bind(struct device *dev, struct device *master, + void *data) +{ + routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL); + if (!routing_data) + return -ENOMEM; + + routing_data->dev = dev; + + mutex_init(&routing_data->lock); + dev_set_drvdata(dev, routing_data); + + return snd_soc_register_component(dev, &msm_soc_routing_component, + NULL, 0); +} + +static void q6routing_dai_unbind(struct device *dev, struct device *master, + void *d) +{ + struct msm_routing_data *data = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + + kfree(data); + + routing_data = NULL; +} + +static const struct component_ops q6routing_dai_comp_ops = { + .bind = q6routing_dai_bind, + .unbind = q6routing_dai_unbind, +}; + +static int q6pcm_routing_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &q6routing_dai_comp_ops); +} + +static int q6pcm_routing_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &q6routing_dai_comp_ops); + return 0; +} + +static struct platform_driver q6pcm_routing_platform_driver = { + .driver = { + .name = "q6routing", + }, + .probe = q6pcm_routing_probe, + .remove = q6pcm_routing_remove, +}; +module_platform_driver(q6pcm_routing_platform_driver); + +MODULE_DESCRIPTION("Q6 Routing platform"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6routing.h b/sound/soc/qcom/qdsp6/q6routing.h new file mode 100644 index 000000000000..35514e651130 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6routing.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _Q6_PCM_ROUTING_H +#define _Q6_PCM_ROUTING_H + +int q6routing_stream_open(int fedai_id, int perf_mode, + int stream_id, int stream_type); +void q6routing_stream_close(int fedai_id, int stream_type); + +#endif /*_Q6_PCM_ROUTING_H */ From patchwork Fri May 18 12:56:06 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136308 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1206405lji; Fri, 18 May 2018 05:59:18 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrUm3yvyu39LKm43U8UpSzdGztQUMwagreOPuSosEstqcGLvkv1banyDTZYNWjfPoyuRRsb X-Received: by 2002:a62:2417:: with SMTP id r23-v6mr9353548pfj.108.1526648358453; Fri, 18 May 2018 05:59:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648358; cv=none; d=google.com; s=arc-20160816; b=REFqZit0EFYsBtcqJ5fycoL14HlDrdWbhKQ6kKtIIr00x+y9Qld35aQJhrV4xhrt4i BYheUEV7xHE+3lCk9zF+UntGUJDrkLJf5caZc70lSyhug9Sl99sr4vmbu2APEP9aCMlB Vu8jNRiRFdyn1rBqX91WnfZX3wUzphQRKnKWMofLx7M6x20RvKjU6V8Aahx2YCx/aKsf 1vmqZax4X0zAfUFgdiV4E0b7q2gLaU4lNxtXKjYXQ40sOeDxn7h/FQ40JlFPdjKE5tq2 PHAa3D0KqhxGTwu9b56NJLNbinPkuXisoiTxFq1xoX79NLoP4SCZNReDv9WmAoPJfKRf l6Tg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=YSdV4FcqMZjxFH88OfU6nBNfAH52pttm2iBQwFp/JtA=; b=zRuNPRbq7QnnMGOcOUgv36Hg7R/1V/vkjIFSuulwTKATYK2S0xcdAm/Juy6GYQfgi0 QYqFPKIzH6k1bIea+EPXoDZYVobPtQzBRIPQYzfgiMb01r5YAH2XvbfGmCkjSnNzlk+i lZoZWpVWV1miPqL1KPaeHBAH0snwJvk0mAWrQSTAyfJv4A2buPoBneLVX0pxKpAVHSpu 0ZxQb2p3CX6aNMvS/fqlLkS1HCagK4yL809kJWyVB6YeXJZnsUbBbYRg3ZYB4ixFfbsk Pnw6YRaqMYevTua40TNwBhX/8SeYzlqWx4ZOkL9/ewpKt/yO24X4WpXyFGw+QiGqXCbY 3xRg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=C8BRVxS2; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id m1-v6si6937599pls.70.2018.05.18.05.59.18; Fri, 18 May 2018 05:59:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=C8BRVxS2; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752334AbeERM7Q (ORCPT + 13 others); Fri, 18 May 2018 08:59:16 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:52651 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752218AbeERM6w (ORCPT ); Fri, 18 May 2018 08:58:52 -0400 Received: by mail-wm0-f68.google.com with SMTP id w194-v6so13919048wmf.2 for ; Fri, 18 May 2018 05:58:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=RqJYWeEk2A53od2W/e2cpRMjrnB4vfEN+54pkeSM048=; b=C8BRVxS2CCrwo3fU2L513VyGwhx6RhPI5R6Z0khImIZi/p5et1S5hcUXQ5JgzVDzJG VLXr7Eopy56yrstqJDp6j5mA0UESLtKF3B9Fm8n+BG/CDhl8W5h9zVXnFCXX++f4+imr QQrS6NxL3Nwmks9yAFi/B+OGdcdV0J08w+xIw= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=RqJYWeEk2A53od2W/e2cpRMjrnB4vfEN+54pkeSM048=; b=hSPVjfCtqlGRpSh+2YFWaNJ5NSJyPLB3pSZsmvEKMm2imgTZ8jaTtT/0ROtkwh3C4/ iPE7qd2lK/1tI1aZ/rfqeP+9nZ+nGGumYQCZ4FP9UPKdMikyZjxqYC3rztmmIfuzyic9 yEmvlIJy8S7vJ5osS3DJkZYUUQEn57wbVgqArT3FFNmHXvOJ5mFpmHjUK7g3YxqrtIMe 2NohbSoJ3/ZlyPQ+Gh+fFi78QFVCK8AxxDdFfMYem15Vls02pl3JrI06NOFxRA69zy1Y F8jdGA+0Conspnfs0W0hu+Nfc/Ye49ZdDWCXvd9lFr6jsHxjPR9IDOeDJkXyPFLvePis H52g== X-Gm-Message-State: ALKqPwd1uwT8Vf9uDW7ATIwYGKVORjNP4ulo63tBT4I/ygJpAG7k/LXk fvp1zQn+xwCs+fps+Ru/94nCbA== X-Received: by 2002:a1c:1d02:: with SMTP id d2-v6mr4397398wmd.44.1526648330502; Fri, 18 May 2018 05:58:50 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:49 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 11/15] ASoC: qdsp6: q6routing: Add support to MI2S Mixers Date: Fri, 18 May 2018 13:56:06 +0100 Message-Id: <20180518125610.26200-12-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch add support to MI2S mixers required to select path between ASM stream and AFE ports. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/qdsp6/q6routing.c | 329 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 329 insertions(+) -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c index 43086913060a..08c25c26adf4 100644 --- a/sound/soc/qcom/qdsp6/q6routing.c +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -241,6 +241,103 @@ static const struct snd_kcontrol_new hdmi_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new primary_mi2s_rx_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", PRIMARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new secondary_mi2s_rx_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", SECONDARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new quaternary_mi2s_rx_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", QUATERNARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new tertiary_mi2s_rx_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", TERTIARY_MI2S_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + + static const struct snd_kcontrol_new slimbus_rx_mixer_controls[] = { SOC_SINGLE_EXT("MultiMedia1", SLIMBUS_0_RX, MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, @@ -415,6 +512,126 @@ static const struct snd_kcontrol_new slimbus_6_rx_mixer_controls[] = { msm_routing_put_audio_mixer), }; +static const struct snd_kcontrol_new mmul1_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul2_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul3_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul4_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul5_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul6_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul7_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_kcontrol_new mmul8_mixer_controls[] = { + SOC_SINGLE_EXT("PRI_MI2S_TX", PRIMARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("QUAT_MI2S_TX", QUATERNARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("TERT_MI2S_TX", TERTIARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("SEC_MI2S_TX", SECONDARY_MI2S_TX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { /* Frontend AIF */ SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0), @@ -460,6 +677,35 @@ static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { SND_SOC_DAPM_MIXER("SLIMBUS_6_RX Audio Mixer", SND_SOC_NOPM, 0, 0, slimbus_6_rx_mixer_controls, ARRAY_SIZE(slimbus_6_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("PRI_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + primary_mi2s_rx_mixer_controls, + ARRAY_SIZE(primary_mi2s_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("SEC_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + secondary_mi2s_rx_mixer_controls, + ARRAY_SIZE(secondary_mi2s_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("QUAT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + quaternary_mi2s_rx_mixer_controls, + ARRAY_SIZE(quaternary_mi2s_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("TERT_MI2S_RX Audio Mixer", SND_SOC_NOPM, 0, 0, + tertiary_mi2s_rx_mixer_controls, + ARRAY_SIZE(tertiary_mi2s_rx_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia1 Mixer", SND_SOC_NOPM, 0, 0, + mmul1_mixer_controls, ARRAY_SIZE(mmul1_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia2 Mixer", SND_SOC_NOPM, 0, 0, + mmul2_mixer_controls, ARRAY_SIZE(mmul2_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia3 Mixer", SND_SOC_NOPM, 0, 0, + mmul3_mixer_controls, ARRAY_SIZE(mmul3_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia4 Mixer", SND_SOC_NOPM, 0, 0, + mmul4_mixer_controls, ARRAY_SIZE(mmul4_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia5 Mixer", SND_SOC_NOPM, 0, 0, + mmul5_mixer_controls, ARRAY_SIZE(mmul5_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia6 Mixer", SND_SOC_NOPM, 0, 0, + mmul6_mixer_controls, ARRAY_SIZE(mmul6_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia7 Mixer", SND_SOC_NOPM, 0, 0, + mmul7_mixer_controls, ARRAY_SIZE(mmul7_mixer_controls)), + SND_SOC_DAPM_MIXER("MultiMedia8 Mixer", SND_SOC_NOPM, 0, 0, + mmul8_mixer_controls, ARRAY_SIZE(mmul8_mixer_controls)), + }; static const struct snd_soc_dapm_route intercon[] = { @@ -537,6 +783,89 @@ static const struct snd_soc_dapm_route intercon[] = { {"SLIMBUS_6_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, {"SLIMBUS_6_RX Audio Mixer", "MultiMedia8", "MM_DL8"}, {"SLIMBUS_6_RX", NULL, "SLIMBUS_6_RX Audio Mixer"}, + + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL6"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, + {"QUAT_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL8"}, + {"QUAT_MI2S_RX", NULL, "QUAT_MI2S_RX Audio Mixer"}, + + {"TERT_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"TERT_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"TERT_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"TERT_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"TERT_MI2S_RX", NULL, "TERT_MI2S_RX Audio Mixer"}, + + {"SEC_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia6", "MM_DL5"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, + {"SEC_MI2S_RX Audio Mixer", "MultiMedia8", "MM_DL7"}, + {"SEC_MI2S_RX", NULL, "SEC_MI2S_RX Audio Mixer"}, + + {"PRI_MI2S_RX Audio Mixer", "MultiMedia1", "MM_DL1"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia2", "MM_DL2"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia3", "MM_DL3"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia4", "MM_DL4"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia5", "MM_DL5"}, + {"PRI_MI2S_RX Audio Mixer", "MultiMedia7", "MM_DL7"}, + {"PRI_MI2S_RX", NULL, "PRI_MI2S_RX Audio Mixer"}, + + {"MultiMedia1 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia1 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia1 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia1 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia2 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia2 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia2 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia2 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia3 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia3 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia3 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia3 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia4 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia4 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia4 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia4 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia5 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia5 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia5 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia5 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia6 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia6 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia6 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia6 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia7 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia7 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia7 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia7 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MultiMedia8 Mixer", "PRI_MI2S_TX", "PRI_MI2S_TX"}, + {"MultiMedia8 Mixer", "SEC_MI2S_TX", "SEC_MI2S_TX"}, + {"MultiMedia8 Mixer", "QUAT_MI2S_TX", "QUAT_MI2S_TX"}, + {"MultiMedia8 Mixer", "TERT_MI2S_TX", "TERT_MI2S_TX"}, + + {"MM_UL1", NULL, "MultiMedia1 Mixer"}, + {"MM_UL2", NULL, "MultiMedia2 Mixer"}, + {"MM_UL3", NULL, "MultiMedia3 Mixer"}, + {"MM_UL4", NULL, "MultiMedia4 Mixer"}, + {"MM_UL5", NULL, "MultiMedia5 Mixer"}, + {"MM_UL6", NULL, "MultiMedia6 Mixer"}, + {"MM_UL7", NULL, "MultiMedia7 Mixer"}, + {"MM_UL8", NULL, "MultiMedia8 Mixer"}, }; static int routing_hw_params(struct snd_pcm_substream *substream, From patchwork Fri May 18 12:56:07 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136310 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1206489lji; Fri, 18 May 2018 05:59:22 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpBFQf2buNwk50HNp6iXd1T2K3+cFPVO2f3G9zH5BRvAdc3JJpktcsLqTdp2SQ/b4dbzL/Z X-Received: by 2002:a17:902:5948:: with SMTP id e8-v6mr9498742plj.121.1526648362354; Fri, 18 May 2018 05:59:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648362; cv=none; d=google.com; s=arc-20160816; b=x1QC36R/DtW6exHawDAhVs7rvgyk2wLzYC3pO1VODBmSB2CQIGNiFMhlrytkBkV5b0 wgiUjpvH0Uf92spgbVQEEQ0sT/bJcRaB/wFM4j45kDfwLD2voxTrEjscWeapAD90M//0 1dS8cbnXWHwrEhN2YeH+P9bS9LPUh5vMQUtNHOrcf9MgGTRztilxJrm6KH808Bsd6rWg 3798eDV+ze7+yXlwBvNVhBR/PiW/uGMs64y8jPLVT1Ukc8ouVqA2q1unIdlrBjk1posS Ba1JFpLMjeWw12S2PcmtTQ3++eCDuwodb+blWVNAt51xjfGVlYWCdthpz5lqSJWbs3EN zHVQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=sj/CXczh3Rn284Ab1xVfFr5QzwuppZ4iFL6I2qz0XqY=; b=JdNzXfXtQ+nCGCeT9vRa6YbK6ttpaKjBk9dXW2UL447cEd273lm+oSrVgjzW/fZflV bDriPISc+7XiVY1taYQ3zxhRCYRYh7rdjtFWZQwkZVSmQO5OD8E1v8wby6l4P8EHIPXD hWARXU58L5d38aRp/rs01cQSUr/6ImwIHpbE7RYi548I3ZQVfyEuRGGfCeoPvj+rDyjM ydAGeDWkXUVm1A6uXPFLYHjdcZpK6LokIosty4uwi1kv0jOpyrsGjluZNmgX+AJFQTq8 Aald+y7fe9ByHQ9CW4GBWCliK2IpS0XAGzpRkt58eA0+SZXQ+MhaXyeybfD77qjaonVr dFfw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=cwpEm1PP; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i65-v6si7819224pfb.343.2018.05.18.05.59.22; Fri, 18 May 2018 05:59:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=cwpEm1PP; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752361AbeERM7U (ORCPT + 13 others); Fri, 18 May 2018 08:59:20 -0400 Received: from mail-wr0-f177.google.com ([209.85.128.177]:37884 "EHLO mail-wr0-f177.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752227AbeERM6x (ORCPT ); Fri, 18 May 2018 08:58:53 -0400 Received: by mail-wr0-f177.google.com with SMTP id h5-v6so9130593wrm.4 for ; Fri, 18 May 2018 05:58:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=vaeK0HJl+LQjUfLeS9E7yzyYFeAp0VOtwlbSbMro3yI=; b=cwpEm1PPYS2FBaHTkwlIMtrMe5u7fBI+zvCKHeboCgcADEJ3yCyq6B+aswOn7A80ty bPWebMsT/cMCTKACVVhOhu3KB8FxGOlT9SmyrOhTa0ZbXUigL3m/TNLVHeWSA73usKJE eRSZpcVCgw+Tt5MiJnA4rUg/AHY0IcPCZQGg8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=vaeK0HJl+LQjUfLeS9E7yzyYFeAp0VOtwlbSbMro3yI=; b=g/yNP12PtkVrEy1MHM2/okatZets0MA9bFJmO3CoWeIwNnCvvZ7BU/F7jWmvO4dIVQ /K202bZiW4K6XuitooGZszc+g/s4J/5dqN2GbP99LI4lRimU+oifzMXZLWO7bkawgurL HXK98kR+CsRZ1SXPNkwmXZ8HOBjGPvWxu3daa3PcvzVCGrBtlh8jwlKjzH15i3aF1Fvz nhjt7mCPUcENvhmjuBVpOkcC/lb6OCZaeWkx3s3vDInywMlQN1unuKIEoMPbHByT5DL7 r51KLDxmExFE1EzhAixteH0fVq33Ih4PblWU+fLPKW5DGB7EFCZJ4mBklgm6zL1jETMR VlDQ== X-Gm-Message-State: ALKqPwevmAFUOd3ewIrxWsA+hqCohFYAEl4vEGf+GBWAE/NNNWaC1Gqd LBOJFHye+qMrdB4ECZcut/dDdw== X-Received: by 2002:adf:a673:: with SMTP id k106-v6mr8202372wrc.231.1526648331913; Fri, 18 May 2018 05:58:51 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:51 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 12/15] ASoC: qdsp6: q6afe: Add q6afe dai driver Date: Fri, 18 May 2018 13:56:07 +0100 Message-Id: <20180518125610.26200-13-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch adds support to q6afe backend dais driver. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6afe-dai.c | 748 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 753 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6afe-dai.c -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 43f9ed85efa8..d3523a30d942 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -50,6 +50,9 @@ config SND_SOC_QDSP6_CORE config SND_SOC_QDSP6_AFE tristate +config SND_SOC_QDSP6_AFE_DAI + tristate + config SND_SOC_QDSP6_ADM tristate @@ -65,6 +68,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_COMMON select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE + select SND_SOC_QDSP6_AFE_DAI select SND_SOC_QDSP6_ADM select SND_SOC_QDSP6_ROUTING select SND_SOC_QDSP6_ASM diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 0e8e2febb7ec..bada1aa303c2 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o +obj-$(CONFIG_SND_SOC_QDSP6_AFE_DAI) += q6afe-dai.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c new file mode 100644 index 000000000000..4378e29a95c5 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6afe.h" + +struct q6afe_dai_priv_data { + uint32_t sd_line_mask; +}; + +struct q6afe_dai_data { + struct q6afe_port *port[AFE_PORT_MAX]; + struct q6afe_port_config port_config[AFE_PORT_MAX]; + bool is_port_started[AFE_PORT_MAX]; + struct q6afe_dai_priv_data priv[AFE_PORT_MAX]; +}; + +static int q6slim_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_slim_cfg *slim = &dai_data->port_config[dai->id].slim; + + slim->num_channels = params_channels(params); + slim->sample_rate = params_rate(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_SPECIAL: + slim->bit_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + slim->bit_width = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + slim->bit_width = 32; + break; + default: + pr_err("%s: format %d\n", + __func__, params_format(params)); + return -EINVAL; + } + + return 0; +} + +static int q6hdmi_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); + int channels = params_channels(params); + struct q6afe_hdmi_cfg *hdmi = &dai_data->port_config[dai->id].hdmi; + + hdmi->sample_rate = params_rate(params); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + hdmi->bit_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + hdmi->bit_width = 24; + break; + } + + /* HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4 */ + switch (channels) { + case 2: + hdmi->channel_allocation = 0; + break; + case 3: + hdmi->channel_allocation = 0x02; + break; + case 4: + hdmi->channel_allocation = 0x06; + break; + case 5: + hdmi->channel_allocation = 0x0A; + break; + case 6: + hdmi->channel_allocation = 0x0B; + break; + case 7: + hdmi->channel_allocation = 0x12; + break; + case 8: + hdmi->channel_allocation = 0x13; + break; + default: + dev_err(dai->dev, "invalid Channels = %u\n", channels); + 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) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg; + + i2s->sample_rate = params_rate(params); + i2s->bit_width = params_width(params); + i2s->num_channels = params_channels(params); + i2s->sd_line_mask = dai_data->priv[dai->id].sd_line_mask; + + return 0; +} + +static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg; + + i2s->fmt = fmt; + + return 0; +} + +static void q6afe_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + rc = q6afe_port_stop(dai_data->port[dai->id]); + if (rc < 0) + dev_err(dai->dev, "fail to close AFE port (%d)\n", rc); + + dai_data->is_port_started[dai->id] = false; + +} + +static int q6afe_mi2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + if (dai_data->is_port_started[dai->id]) { + /* stop the port and restart with new port config */ + rc = q6afe_port_stop(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to close AFE port (%d)\n", rc); + return rc; + } + } + + rc = q6afe_i2s_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].i2s_cfg); + if (rc < 0) { + dev_err(dai->dev, "fail to prepare AFE port %x\n", dai->id); + return rc; + } + + rc = q6afe_port_start(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to start AFE port %x\n", dai->id); + return rc; + } + dai_data->is_port_started[dai->id] = true; + + return 0; +} + +static int q6afe_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + if (dai_data->is_port_started[dai->id]) { + /* stop the port and restart with new port config */ + rc = q6afe_port_stop(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to close AFE port (%d)\n", rc); + return rc; + } + } + + if (dai->id == HDMI_RX) + q6afe_hdmi_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].hdmi); + else if (dai->id >= SLIMBUS_0_RX && dai->id <= SLIMBUS_6_TX) + q6afe_slim_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].slim); + + rc = q6afe_port_start(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to start AFE port %x\n", dai->id); + return rc; + } + dai_data->is_port_started[dai->id] = true; + + return 0; +} + +static int q6slim_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id]; + int i; + + if (!rx_slot) { + pr_err("%s: rx slot not found\n", __func__); + return -EINVAL; + } + + for (i = 0; i < rx_num; i++) { + pcfg->slim.ch_mapping[i] = rx_slot[i]; + pr_debug("%s: find number of channels[%d] ch[%d]\n", + __func__, i, rx_slot[i]); + } + + pcfg->slim.num_channels = rx_num; + + pr_debug("%s: SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__, + (dai->id - SLIMBUS_0_RX) / 2, rx_num, + pcfg->slim.ch_mapping[0], + pcfg->slim.ch_mapping[1]); + + return 0; +} + +static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_port *port = dai_data->port[dai->id]; + + switch (clk_id) { + case LPAIF_DIG_CLK: + return q6afe_port_set_sysclk(port, clk_id, 0, 5, freq, dir); + case LPAIF_BIT_CLK: + case LPAIF_OSR_CLK: + return q6afe_port_set_sysclk(port, clk_id, + Q6AFE_LPASS_CLK_SRC_INTERNAL, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + freq, dir); + case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... 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); + } + + return 0; +} + +static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { + {"HDMI Playback", NULL, "HDMI_RX"}, + {"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"}, + {"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"}, + {"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"}, + {"Slimbus4 Playback", NULL, "SLIMBUS_4_RX"}, + {"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"}, + {"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"}, + + {"Primary MI2S Playback", NULL, "PRI_MI2S_RX"}, + {"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"}, + {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"}, + {"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"}, + + {"TERT_MI2S_TX", NULL, "Tertiary MI2S Capture"}, + {"PRI_MI2S_TX", NULL, "Primary MI2S Capture"}, + {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"}, + {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, +}; + +static struct snd_soc_dai_ops q6hdmi_ops = { + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, +}; + +static struct snd_soc_dai_ops q6i2s_ops = { + .prepare = q6afe_mi2s_prepare, + .hw_params = q6i2s_hw_params, + .set_fmt = q6i2s_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + +static struct snd_soc_dai_ops q6slim_ops = { + .prepare = q6afe_dai_prepare, + .hw_params = q6slim_hw_params, + .shutdown = q6afe_dai_shutdown, + .set_channel_map = q6slim_set_channel_map, +}; + +static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_port *port; + + port = q6afe_port_get_from_id(dai->dev, dai->id); + if (IS_ERR(port)) { + dev_err(dai->dev, "Unable to get afe port\n"); + return -EINVAL; + } + dai_data->port[dai->id] = port; + + return 0; +} + +static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + + q6afe_port_put(dai_data->port[dai->id]); + dai_data->port[dai->id] = NULL; + + return 0; +} + +static struct snd_soc_dai_driver q6afe_dais[] = { + { + .playback = { + .stream_name = "HDMI Playback", + .rates = SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 8, + .rate_max = 192000, + .rate_min = 48000, + }, + .ops = &q6hdmi_ops, + .id = HDMI_RX, + .name = "HDMI", + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .name = "SLIMBUS_0_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_0_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .playback = { + .stream_name = "Slimbus Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 192000, + }, + }, { + .playback = { + .stream_name = "Slimbus1 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_1_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_1_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus2 Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_2_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_2_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus3 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_3_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_3_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus4 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_4_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_4_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus5 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_5_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_5_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus6 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .ops = &q6slim_ops, + .name = "SLIMBUS_6_RX", + .id = SLIMBUS_6_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Primary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = PRIMARY_MI2S_RX, + .name = "PRI_MI2S_RX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Primary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = PRIMARY_MI2S_TX, + .name = "PRI_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Secondary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .name = "SEC_MI2S_RX", + .id = SECONDARY_MI2S_RX, + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Secondary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = SECONDARY_MI2S_TX, + .name = "SEC_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Tertiary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .name = "TERT_MI2S_RX", + .id = TERTIARY_MI2S_RX, + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Tertiary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = TERTIARY_MI2S_TX, + .name = "TERT_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Quaternary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .name = "QUAT_MI2S_RX", + .id = QUATERNARY_MI2S_RX, + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Quaternary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = QUATERNARY_MI2S_TX, + .name = "QUAT_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, +}; + +static int q6afe_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name) +{ + int id = args->args[0]; + int ret = -EINVAL; + int i; + + for (i = 0; i < ARRAY_SIZE(q6afe_dais); i++) { + if (q6afe_dais[i].id == id) { + *dai_name = q6afe_dais[i].name; + ret = 0; + break; + } + } + + return ret; +} + +static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { + SND_SOC_DAPM_AIF_OUT("HDMI_RX", "HDMI Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_RX", "Slimbus6 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX_SD1", + "Secondary MI2S Playback SD1", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture", + 0, 0, 0, 0), +}; + +static const struct snd_soc_component_driver q6afe_dai_component = { + .name = "q6afe-dai-component", + .dapm_widgets = q6afe_dai_widgets, + .num_dapm_widgets = ARRAY_SIZE(q6afe_dai_widgets), + .dapm_routes = q6afe_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(q6afe_dapm_routes), + .of_xlate_dai_name = q6afe_of_xlate_dai_name, + +}; + +static void of_q6afe_parse_dai_data(struct device *dev, + struct q6afe_dai_data *data) +{ + struct device_node *node; + int ret; + + for_each_child_of_node(dev->of_node, node) { + unsigned int lines[Q6AFE_MAX_MI2S_LINES]; + struct q6afe_dai_priv_data *priv; + int id, i, num_lines; + + ret = of_property_read_u32(node, "reg", &id); + if (ret || id > AFE_PORT_MAX) { + dev_err(dev, "valid dai id not found:%d\n", ret); + continue; + } + + switch (id) { + /* MI2S specific properties */ + case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + priv = &data->priv[id]; + ret = of_property_read_variable_u32_array(node, + "qcom,sd-lines", + lines, 0, + Q6AFE_MAX_MI2S_LINES); + if (ret < 0) + num_lines = 0; + else + num_lines = ret; + + priv->sd_line_mask = 0; + + for (i = 0; i < num_lines; i++) + priv->sd_line_mask |= BIT(lines[i]); + + break; + default: + break; + } + } +} + +static int q6afe_dai_bind(struct device *dev, struct device *master, void *data) +{ + struct q6afe_dai_data *dai_data; + + dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL); + if (!dai_data) + return -ENOMEM; + + dev_set_drvdata(dev, dai_data); + + of_q6afe_parse_dai_data(dev, dai_data); + + return snd_soc_register_component(dev, &q6afe_dai_component, + q6afe_dais, ARRAY_SIZE(q6afe_dais)); +} + +static void q6afe_dai_unbind(struct device *dev, struct device *master, + void *data) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + kfree(dai_data); +} + +static const struct component_ops q6afe_dai_comp_ops = { + .bind = q6afe_dai_bind, + .unbind = q6afe_dai_unbind, +}; + +static int q6afe_dai_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &q6afe_dai_comp_ops); +} + +static int q6afe_dai_dev_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &q6afe_dai_comp_ops); + return 0; +} + +static struct platform_driver q6afe_dai_platform_driver = { + .driver = { + .name = "q6afe-dai", + }, + .probe = q6afe_dai_dev_probe, + .remove = q6afe_dai_dev_remove, +}; +module_platform_driver(q6afe_dai_platform_driver); + +MODULE_DESCRIPTION("Q6 Audio Fronend dai driver"); +MODULE_LICENSE("GPL v2"); From patchwork Fri May 18 12:56:10 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 136315 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp1207636lji; Fri, 18 May 2018 06:00:21 -0700 (PDT) X-Google-Smtp-Source: AB8JxZoSt2abe8XvyUpG1NnJrX9WQXqqi/maFRTiSJV3aR4m9bACxLESh7Dti5IXoVYN4c6lzDXP X-Received: by 2002:a62:66dd:: with SMTP id s90-v6mr9228043pfj.123.1526648421347; Fri, 18 May 2018 06:00:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1526648421; cv=none; d=google.com; s=arc-20160816; b=zeI48DmF01FhnglyMbYc0INGtG46ZxWITmdxM9NteO0b/Pcuu2d27A26ED5fZF6ZPp bBpRB6AdEI01SMRx9Qx8TFqiLK1TWOnk/aFSwwxnVyTnJK7KwIUIQU2WX5jkBnaiy2Us TZVgVlWO23odG1XRSI7xuEYh2GHAgxxz1dI+aMnOGT3KZ7+kA0x8tSwBYjsHoiv6OBiX cDIy2bOf2i6p5hkhOjRuWb1Av8zCVpE/RJ+7pQnBl2hprfUnRNH0V6i5jCll4SdLPMOu xJJfF4Q6kSPcYEJcMgE6OQzBJkIykI0chIgi3SvokEc3TMejkfihTORDT7ZpAHiOaRGP e98w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=SIFAOQSDWA/W6/+sfDzfJ3fyop19CiHkf1jw0hUW8kg=; b=AnXOpPpQ6U4pknPm4VzaXlttthBbXnGhOb+4dK+sfnj4SwNWCE1JmKFr3tYOLmrUvf cHVuQGCXYuM3ARcm1fzpze6xP6n3Ov36xzbo5Tl4J+0sGom7rlD6QeHM82dtme4V+iac Rx32ZbNLvG/cnMnn5jBYkv5m3nE8FAArf1Gf6nsF5pTr0YkR8rpGkwySLzmsUa4+P0RN q4eV0EaGOeiy148o0tadGknjyy4cST/WjBNdbVu/+TEm7h9m/GbLJCCQyLHj4wLIIQDI 3GcI44g9M/jHb/EahM8F0f0yod77iuRD9KQNUC9L7Fxe9Z8KTnfbP6P+NnjlGFlHLkzw Quhw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=JE43rFob; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l9-v6si1762766pgs.11.2018.05.18.06.00.21; Fri, 18 May 2018 06:00:21 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=JE43rFob; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752242AbeERNAT (ORCPT + 13 others); Fri, 18 May 2018 09:00:19 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:33818 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752243AbeERM65 (ORCPT ); Fri, 18 May 2018 08:58:57 -0400 Received: by mail-wm0-f68.google.com with SMTP id a137-v6so3397043wme.1 for ; Fri, 18 May 2018 05:58:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=uHDANnwKRCQYe/vXiaw+Vr+9LLesAapc457Ky6dGrxg=; b=JE43rFobkR8VwRaR4G4+NsaFyuxBGuuWUZo7CRwWbOTGqv2pcFLSJlEkIDRVLN9ydX OQmPTM55M+Ewt1LdhsA2e8fcLQk+UsfiPyZmzegzCZGNN6e7O1jruNS10Bra3umTpqF7 KSFeiBNaPNoyBdy8sfoiakYV0ewTeQwlB/BaU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=uHDANnwKRCQYe/vXiaw+Vr+9LLesAapc457Ky6dGrxg=; b=QfsqOsAVo9UKI+GdcDgF8qRwrJJM3GfYirCXhMkJ1o84UgMH8d6EBOcdPSpPpfR/nm V+tjcsHGjwxNSfS8FjU1QnzwlLphTV8ub2lRVRYScIMOc9qWJswNfo0L/vnfeF0yILtk HN5ARo795H+8EXl6FNmw8BhXKGFonRHU865bGP4abm+bGX2bQdwardE/Nt170bxkQWQS qm901X6wiwatv5lfp/nvsPCItsAMcTEXJ/AtwwiwYU0jW6NTpM+ng7VqDA8zBB4LLfGC R+MDWVx+/fuW1eg2F15++XTNR2csCYl18bpEnjXHDqle42smv011/zj/IJHnJWf9QMSr 8PrQ== X-Gm-Message-State: ALKqPweSqCfssveAa2+jAvQxshY6fjJ31aO4zSy06j+MjWmGCDhQcsCM ispoHkIP2JSq0ASCiURQFyTCCQ== X-Received: by 2002:a1c:9e90:: with SMTP id h138-v6mr4668975wme.33.1526648335877; Fri, 18 May 2018 05:58:55 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id x7-v6sm7868034wrm.35.2018.05.18.05.58.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 18 May 2018 05:58:55 -0700 (PDT) From: Srinivas Kandagatla To: broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org Cc: robh+dt@kernel.org, gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v9 15/15] ASoC: qcom: apq8096: Add db820c machine driver Date: Fri, 18 May 2018 13:56:10 +0100 Message-Id: <20180518125610.26200-16-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> References: <20180518125610.26200-1-srinivas.kandagatla@linaro.org> Sender: linux-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org This patch adds support to DB820c machine driver. Signed-off-by: Srinivas Kandagatla Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 9 ++ sound/soc/qcom/Makefile | 2 + sound/soc/qcom/apq8096.c | 255 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+) create mode 100644 sound/soc/qcom/apq8096.c -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 85bb7dd11fd9..87838fa27997 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -81,3 +81,12 @@ config SND_SOC_QDSP6 This will enable sound soc platform specific audio drivers. This includes q6asm, q6adm, q6afe interfaces to DSP using apr. + +config SND_SOC_MSM8996 + tristate "SoC Machine driver for MSM8996 and APQ8096 boards" + depends on QCOM_APR + select SND_SOC_QDSP6 + help + Support for Qualcomm Technologies LPASS audio block in + APQ8096 SoC-based systems. + Say Y if you want to use audio device on this SoCs diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index 0276717917c0..206945bb9ba1 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -13,9 +13,11 @@ obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o # Machine snd-soc-storm-objs := storm.o snd-soc-apq8016-sbc-objs := apq8016_sbc.o +snd-soc-apq8096-objs := apq8096.o obj-$(CONFIG_SND_SOC_STORM) += snd-soc-storm.o obj-$(CONFIG_SND_SOC_APQ8016_SBC) += snd-soc-apq8016-sbc.o +obj-$(CONFIG_SND_SOC_MSM8996) += snd-soc-apq8096.o #DSP lib obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/ diff --git a/sound/soc/qcom/apq8096.c b/sound/soc/qcom/apq8096.c new file mode 100644 index 000000000000..561cd429e6f2 --- /dev/null +++ b/sound/soc/qcom/apq8096.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} + +static int apq8096_sbc_parse_of(struct snd_soc_card *card) +{ + struct device_node *np; + struct device_node *codec = NULL; + struct device_node *platform = NULL; + struct device_node *cpu = NULL; + struct device *dev = card->dev; + struct snd_soc_dai_link *link; + int ret, num_links; + + ret = snd_soc_of_parse_card_name(card, "qcom,model"); + if (ret) { + dev_err(dev, "Error parsing card name: %d\n", ret); + return ret; + } + + /* DAPM routes */ + if (of_property_read_bool(dev->of_node, "qcom,audio-routing")) { + ret = snd_soc_of_parse_audio_routing(card, + "qcom,audio-routing"); + if (ret) + return ret; + } + + /* Populate links */ + num_links = of_get_child_count(dev->of_node); + + /* Allocate the DAI link array */ + card->dai_link = kcalloc(num_links, sizeof(*link), GFP_KERNEL); + if (!card->dai_link) + return -ENOMEM; + + card->num_links = num_links; + link = card->dai_link; + + for_each_child_of_node(dev->of_node, np) { + cpu = of_get_child_by_name(np, "cpu"); + if (!cpu) { + dev_err(dev, "Can't find cpu DT node\n"); + ret = -EINVAL; + goto err; + } + + link->cpu_of_node = of_parse_phandle(cpu, "sound-dai", 0); + if (!link->cpu_of_node) { + dev_err(card->dev, "error getting cpu phandle\n"); + ret = -EINVAL; + goto err; + } + + ret = snd_soc_of_get_dai_name(cpu, &link->cpu_dai_name); + if (ret) { + dev_err(card->dev, "error getting cpu dai name\n"); + goto err; + } + + platform = of_get_child_by_name(np, "platform"); + codec = of_get_child_by_name(np, "codec"); + if (codec && platform) { + link->platform_of_node = of_parse_phandle(platform, + "sound-dai", + 0); + if (!link->platform_of_node) { + dev_err(card->dev, "platform dai not found\n"); + ret = -EINVAL; + goto err; + } + + ret = snd_soc_of_get_dai_link_codecs(dev, codec, link); + if (ret < 0) { + dev_err(card->dev, "codec dai not found\n"); + goto err; + } + link->no_pcm = 1; + link->ignore_pmdown_time = 1; + link->be_hw_params_fixup = apq8096_be_hw_params_fixup; + } else { + link->platform_of_node = link->cpu_of_node; + link->codec_dai_name = "snd-soc-dummy-dai"; + link->codec_name = "snd-soc-dummy"; + link->dynamic = 1; + } + + link->ignore_suspend = 1; + ret = of_property_read_string(np, "link-name", &link->name); + if (ret) { + dev_err(card->dev, "error getting codec dai_link name\n"); + goto err; + } + + link->dpcm_playback = 1; + link->dpcm_capture = 1; + link->stream_name = link->name; + link++; + } + + return 0; +err: + of_node_put(cpu); + of_node_put(codec); + of_node_put(platform); + kfree(card->dai_link); + return ret; +} + +static int apq8096_bind(struct device *dev) +{ + struct snd_soc_card *card; + int ret; + + card = kzalloc(sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + component_bind_all(dev, card); + card->dev = dev; + ret = apq8096_sbc_parse_of(card); + if (ret) { + dev_err(dev, "Error parsing OF data\n"); + goto err; + } + + ret = snd_soc_register_card(card); + if (ret) + goto err; + + return 0; + +err: + component_unbind_all(dev, card); + kfree(card); + return ret; +} + +static void apq8096_unbind(struct device *dev) +{ + struct snd_soc_card *card = dev_get_drvdata(dev); + + snd_soc_unregister_card(card); + component_unbind_all(dev, card); + kfree(card->dai_link); + kfree(card); +} + +static const struct component_master_ops apq8096_ops = { + .bind = apq8096_bind, + .unbind = apq8096_unbind, +}; + +static int apq8016_compare_of(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +static void apq8016_release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + +static int add_audio_components(struct device *dev, + struct component_match **matchptr) +{ + struct device_node *np, *platform, *cpu, *node, *dai_node; + + node = dev->of_node; + + for_each_child_of_node(node, np) { + cpu = of_get_child_by_name(np, "cpu"); + if (cpu) { + dai_node = of_parse_phandle(cpu, "sound-dai", 0); + of_node_get(dai_node); + component_match_add_release(dev, matchptr, + apq8016_release_of, + apq8016_compare_of, + dai_node); + } + + platform = of_get_child_by_name(np, "platform"); + if (platform) { + dai_node = of_parse_phandle(platform, "sound-dai", 0); + component_match_add_release(dev, matchptr, + apq8016_release_of, + apq8016_compare_of, + dai_node); + } + } + + return 0; +} + +static int apq8096_platform_probe(struct platform_device *pdev) +{ + struct component_match *match = NULL; + int ret; + + ret = add_audio_components(&pdev->dev, &match); + if (ret) + return ret; + + return component_master_add_with_match(&pdev->dev, &apq8096_ops, match); +} + +static int apq8096_platform_remove(struct platform_device *pdev) +{ + component_master_del(&pdev->dev, &apq8096_ops); + + return 0; +} + +static const struct of_device_id msm_snd_apq8096_dt_match[] = { + {.compatible = "qcom,apq8096-sndcard"}, + {} +}; + +MODULE_DEVICE_TABLE(of, msm_snd_apq8096_dt_match); + +static struct platform_driver msm_snd_apq8096_driver = { + .probe = apq8096_platform_probe, + .remove = apq8096_platform_remove, + .driver = { + .name = "msm-snd-apq8096", + .owner = THIS_MODULE, + .of_match_table = msm_snd_apq8096_dt_match, + }, +}; +module_platform_driver(msm_snd_apq8096_driver); +MODULE_AUTHOR("Srinivas Kandagatla