From patchwork Tue Dec 5 22:18:01 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 120772 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp6314615qgn; Tue, 5 Dec 2017 14:24:36 -0800 (PST) X-Google-Smtp-Source: AGs4zMYDL5EyRA1CqGSe77jZqSj1g4UdCYy8/71+jfk0ZcrK5TajoAc4XYXkZaBDPQfl+zSxBg5X X-Received: by 10.84.241.6 with SMTP id a6mr20293086pll.318.1512512676588; Tue, 05 Dec 2017 14:24:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512512676; cv=none; d=google.com; s=arc-20160816; b=rdsumtHFPVyH6cHFYTCfoi/sy95KpcxUd6jtxzAaQL945rfo4xYTAPpML0iaFp4Tn/ NoAL6h2U61qnHMP88QyE31auKXIuEC6pdWvFN7kAMKdEWLZjwW2z/HPI2mntX/uyfaRY QGL6keGv53KJly54ttiAG08GaVVHC1+SAU1lB5GVbt+AT6e2l8c3GkF7JIC3mYZuBH6G kpTtKL9vijRfz5Lp8+TOd6j/Zcjw+zWh8arBxCsj/q8+CjFs7YxSnyy3U1FszlhCiD6v aWrfn9RvZg7k4uBxJUc+zFwfcOJltCndzUb8n/3BJetgXgKhWqmBjbb/bLbc4nUsk3aO /OJg== 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=Z3Y6Z0MQcA4FYveJbnsFhVF/EVbsAASTgHjZkRe0y1U=; b=PARSNJnRlxv00U3Ll8/gK/52alsSie+9yn6EjJMPfrwXagVmK5yIxzJUL9Yr/L194E oVaASs7UuHqPmnrVTAGyekWV9sTfkdjevE2Mjg3sBkLCAvFhFuVEwl8kOBKQx9C2oX6l eslug/KgCOA51pie0+PxALUNeQ7EqMv+cKfVLLu3muO9cHYz7uw+qY4tL+9aBS1dpd9f jqYU4d7A42FBVwAdFaDU81wOJAUdUY1R9QFjLq1hQtFh+oxC7WQsvVhNv5eUGhTOiskK VLU9S+pvqF2xOpPn2jmhQ30dqOvEE2qscygNkrpb4MF68gBe/yXIBv25NQmDnqDY0h0a ZhwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=K3vrw7Qa; 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 m8si797091pfi.343.2017.12.05.14.24.36; Tue, 05 Dec 2017 14:24:36 -0800 (PST) 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=K3vrw7Qa; 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 S1752938AbdLEWYe (ORCPT + 10 others); Tue, 5 Dec 2017 17:24:34 -0500 Received: from mail-wm0-f67.google.com ([74.125.82.67]:38570 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752426AbdLEWUZ (ORCPT ); Tue, 5 Dec 2017 17:20:25 -0500 Received: by mail-wm0-f67.google.com with SMTP id 64so3954904wme.3 for ; Tue, 05 Dec 2017 14:20:24 -0800 (PST) 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=9VzAAILnrxpGQ6RseLTT1tRbq7b2G+3CuK2mLJg0cjA=; b=K3vrw7QajFUxLSYnnUEy+PB/jEiq7D9wTdmtmGpgxw/R48bmRkYgbt7D9/Z2mMooFd ft853fd26x5YxFTQ+cZxJSyU6Oom6nOACRmzXqZbSBFeVnC36zYw/WoM80vKTqrzViGP JNch//vBgp1FF4Nz6xQGfGcuJUkPmFYtMTBlo= 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=9VzAAILnrxpGQ6RseLTT1tRbq7b2G+3CuK2mLJg0cjA=; b=uWGhXH2TFkRPUrGSTnnrkvWzG44P7plP5vZ1Mpoj97brrKvbUXWT0j/3xWiOYfurii lJaVMaoTDu+pPrNlTgZyWVlSJJEBTngpgRF7hpdCjcA0qoSLv19pqo4EkqafyfIBKLGx P/I2YxAu8l1JUIdBz6ueGNAOvk1OWGLrmpkTcc41xIy8WM8Epn39Heb4YMVY8jv5rnaX 4u3mr4VODV4YrCQlgrLDr/4ucR2Y7ClKEbQMQ20ZE66dMw/ubNMEWAQHh+XTYkj/lZ3I bgXK+K7GFQacu+lWLPHdrIgYBDVPvQw6laQh+f2lu/u7RWKyGVG8X//RTNRhYVIOoGl3 x15w== X-Gm-Message-State: AJaThX6HQaehEG0G9JIE7RGdWsPId2vpuJDiSUeGthgj1Ev7vlZYaooR v7fohDCwmT8JjTuEKLaphbs3UQ== X-Received: by 10.28.130.208 with SMTP id e199mr10981301wmd.75.1512512423559; Tue, 05 Dec 2017 14:20:23 -0800 (PST) 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 t138sm1633154wme.16.2017.12.05.14.20.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 05 Dec 2017 14:20:23 -0800 (PST) From: srinivas.kandagatla@linaro.org To: broonie@kernel.org, bgoswami@codeaurora.org Cc: alsa-devel@alsa-project.org, tiwai@suse.com, plai@codeaurora.org, kwestfie@codeaurora.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, lkasam@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v2 04/15] ASoC: qcom: qdsp6: Add support to Q6AFE Date: Tue, 5 Dec 2017 22:18:01 +0000 Message-Id: <20171205221812.25641-5-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171205221812.25641-1-srinivas.kandagatla@linaro.org> References: <20171205221812.25641-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 From: Srinivas Kandagatla This patch adds support to q6 AFE (Audio Front End) module on Q6DSP. AFE module sits right at the other end of cpu where the codec/audio devices are connected. AFE provides abstraced interfaces to both hardware and virtual devices. Each AFE tx/rx port can be configured to connect to one of the hardware devices like codec, hdmi, slimbus, i2s and so on. AFE services include starting, stopping, and if needed, any configurations of the ports. Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/Kconfig | 13 ++ sound/soc/qcom/Makefile | 5 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6afe.c | 503 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6afe.h | 30 +++ 5 files changed, 552 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/Makefile create mode 100644 sound/soc/qcom/qdsp6/q6afe.c create mode 100644 sound/soc/qcom/qdsp6/q6afe.h -- 2.15.0 -- 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 8ec9a074b38b..1db92069a6a0 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -43,3 +43,16 @@ config SND_SOC_APQ8016_SBC Support for Qualcomm Technologies LPASS audio block in APQ8016 SOC-based systems. Say Y if you want to use audio devices on MI2S. + +config SND_SOC_QDSP6_AFE + tristate + default n + +config SND_SOC_QDSP6 + tristate "SoC ALSA audio driver for QDSP6" + select SND_SOC_QDSP6_AFE + help + To add support for MSM QDSP6 Soc Audio. + This will enable sound soc platform specific + audio drivers. This includes q6asm, q6adm, + q6afe interfaces to DSP using apr. diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile index d5280355c24f..748f5e891dcf 100644 --- a/sound/soc/qcom/Makefile +++ b/sound/soc/qcom/Makefile @@ -13,6 +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-msm8996-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-msm8996.o + +#DSP lib +obj-$(CONFIG_SND_SOC_QDSP6) += qdsp6/ diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile new file mode 100644 index 000000000000..313e65f571db --- /dev/null +++ b/sound/soc/qcom/qdsp6/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c new file mode 100644 index 000000000000..a6a782e6f17d --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -0,0 +1,503 @@ +/* SPDX-License-Identifier: GPL-2.0 +* Copyright (c) 2011-2016, The Linux Foundation +* Copyright (c) 2017, Linaro Limited +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "q6afe.h" + +/* AFE CMDs */ +#define AFE_PORT_CMD_DEVICE_START 0x000100E5 +#define AFE_PORT_CMD_DEVICE_STOP 0x000100E6 +#define AFE_PORT_CMD_SET_PARAM_V2 0x000100EF +#define AFE_PORT_CMDRSP_GET_PARAM_V2 0x00010106 +#define AFE_PARAM_ID_HDMI_CONFIG 0x00010210 +#define AFE_MODULE_AUDIO_DEV_INTERFACE 0x0001020C + +/* Port IDs */ +#define AFE_API_VERSION_HDMI_CONFIG 0x1 +#define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E +#define TIMEOUT_MS 1000 +#define AFE_CMD_RESP_AVAIL 0 +#define AFE_CMD_RESP_NONE 1 + + +struct q6afev2 { + void *apr; + struct device *dev; + int state; + int status; + struct platform_device *daidev; + + struct mutex afe_cmd_lock; + struct list_head port_list; + spinlock_t port_list_lock; + struct list_head node; +}; + +struct afe_port_cmd_device_start { + struct apr_hdr hdr; + u16 port_id; + u16 reserved; +} __packed; + +struct afe_port_cmd_device_stop { + struct apr_hdr hdr; + u16 port_id; + u16 reserved; +/* Reserved for 32-bit alignment. This field must be set to 0.*/ +} __packed; + +struct afe_port_param_data_v2 { + u32 module_id; + u32 param_id; + u16 param_size; + u16 reserved; +} __packed; + +struct afe_port_cmd_set_param_v2 { + u16 port_id; + u16 payload_size; + u32 payload_address_lsw; + u32 payload_address_msw; + u32 mem_map_handle; +} __packed; + +struct afe_param_id_hdmi_multi_chan_audio_cfg { + u32 hdmi_cfg_minor_version; + u16 datatype; + u16 channel_allocation; + u32 sample_rate; + u16 bit_width; + u16 reserved; +} __packed; + +union afe_port_config { + struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch; +} __packed; + +struct q6afe_port { + wait_queue_head_t wait; + union afe_port_config port_cfg; + int token; + int id; + int cfg_type; + union { + struct q6afev2 *v2; + } afe; + struct list_head node; +}; + +struct afe_audioif_config_command { + struct apr_hdr hdr; + struct afe_port_cmd_set_param_v2 param; + struct afe_port_param_data_v2 pdata; + union afe_port_config port; +} __packed; + +struct afe_port_map { + int port_id; + int token; + int is_rx; +}; + +/* Port map of index vs real hw port ids */ +static struct afe_port_map port_maps[AFE_PORT_MAX] = { + [AFE_PORT_HDMI_RX] = { AFE_PORT_ID_MULTICHAN_HDMI_RX, + AFE_PORT_HDMI_RX, 1}, +}; + +static struct q6afe_port *afe_find_port(struct q6afev2 *afe, int token) +{ + struct q6afe_port *p = NULL; + + spin_lock(&afe->port_list_lock); + list_for_each_entry(p, &afe->port_list, node) + if (p->token == token) + break; + + spin_unlock(&afe->port_list_lock); + return p; +} + +static int afe_callback(struct apr_device *adev, struct apr_client_data *data) +{ + struct q6afev2 *afe = dev_get_drvdata(&adev->dev);//priv; + struct q6afe_port *port; + + if (!data) { + dev_err(afe->dev, "%s: Invalid param data\n", __func__); + return -EINVAL; + } + + if (data->payload_size) { + uint32_t *payload = data->payload; + + if (data->opcode == APR_BASIC_RSP_RESULT) { + if (payload[1] != 0) { + afe->status = payload[1]; + dev_err(afe->dev, + "cmd = 0x%x returned error = 0x%x\n", + payload[0], payload[1]); + } + switch (payload[0]) { + case AFE_PORT_CMD_SET_PARAM_V2: + case AFE_PORT_CMD_DEVICE_STOP: + case AFE_PORT_CMD_DEVICE_START: + afe->state = AFE_CMD_RESP_AVAIL; + port = afe_find_port(afe, data->token); + if (port) + wake_up(&port->wait); + + break; + default: + dev_err(afe->dev, "Unknown cmd 0x%x\n", + payload[0]); + break; + } + } + } + return 0; +} +/** + * q6afe_get_port_id() - Get port id from a given port index + * + * @index: port index + * + * Return: Will be an negative on error or valid port_id on success + */ +int q6afe_get_port_id(int index) +{ + if (index < 0 || index > AFE_PORT_MAX) + return -EINVAL; + + return port_maps[index].port_id; +} +EXPORT_SYMBOL_GPL(q6afe_get_port_id); + +static int afe_apr_send_pkt(struct q6afev2 *afe, void *data, + wait_queue_head_t *wait) +{ + int ret; + + if (wait) + afe->state = AFE_CMD_RESP_NONE; + + afe->status = 0; + ret = apr_send_pkt(afe->apr, data); + if (ret > 0) { + if (wait) { + ret = wait_event_timeout(*wait, + (afe->state == + AFE_CMD_RESP_AVAIL), + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + ret = -ETIMEDOUT; + } else if (afe->status > 0) { + dev_err(afe->dev, "DSP returned error[%s]\n", + adsp_err_get_err_str(afe->status)); + ret = adsp_err_get_lnx_err_code(afe->status); + } else { + ret = 0; + } + } else { + ret = 0; + } + } else { + dev_err(afe->dev, "packet not transmitted\n"); + ret = -EINVAL; + } + + return ret; +} + +static int afe_send_cmd_port_start(struct q6afe_port *port) +{ + u16 port_id = port->id; + struct afe_port_cmd_device_start start; + struct q6afev2 *afe = port->afe.v2; + int ret, index; + + index = port->token; + start.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + start.hdr.pkt_size = sizeof(start); + start.hdr.src_port = 0; + start.hdr.dest_port = 0; + start.hdr.token = index; + start.hdr.opcode = AFE_PORT_CMD_DEVICE_START; + start.port_id = port_id; + + ret = afe_apr_send_pkt(afe, &start, &port->wait); + if (ret) + dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n", + port_id, ret); + + return ret; +} + +static int afe_port_start(struct q6afe_port *port, + union afe_port_config *afe_config) +{ + struct afe_audioif_config_command config; + struct q6afev2 *afe = port->afe.v2; + int ret = 0; + int port_id = port->id; + int cfg_type; + int index = 0; + + if (!afe_config) { + dev_err(afe->dev, "Error, no configuration data\n"); + ret = -EINVAL; + return ret; + } + + index = port->token; + + mutex_lock(&afe->afe_cmd_lock); + /* Also send the topology id here: */ + config.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + config.hdr.pkt_size = sizeof(config); + config.hdr.src_port = 0; + config.hdr.dest_port = 0; + config.hdr.token = index; + + cfg_type = port->cfg_type; + config.hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + config.param.port_id = port_id; + config.param.payload_size = sizeof(config) - sizeof(struct apr_hdr) - + sizeof(config.param); + config.param.payload_address_lsw = 0x00; + config.param.payload_address_msw = 0x00; + config.param.mem_map_handle = 0x00; + config.pdata.module_id = AFE_MODULE_AUDIO_DEV_INTERFACE; + config.pdata.param_id = cfg_type; + config.pdata.param_size = sizeof(config.port); + + config.port = *afe_config; + + ret = afe_apr_send_pkt(afe, &config, &port->wait); + if (ret) { + dev_err(afe->dev, "AFE enable for port 0x%x failed %d\n", + port_id, ret); + goto fail_cmd; + } + + ret = afe_send_cmd_port_start(port); + +fail_cmd: + mutex_unlock(&afe->afe_cmd_lock); + return ret; +} + +/** + * q6afe_port_stop() - Stop a afe port + * + * @port: Instance of port to stop + * + * Return: Will be an negative on packet size on success. + */ +int q6afe_port_stop(struct q6afe_port *port) +{ + int port_id = port->id; + struct afe_port_cmd_device_stop stop; + struct q6afev2 *afe = port->afe.v2; + int ret = 0; + int index = 0; + + port_id = port->id; + index = port->token; + if (index < 0 || index > AFE_PORT_MAX) { + dev_err(afe->dev, "AFE port index[%d] invalid!\n", index); + return -EINVAL; + } + + stop.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + stop.hdr.pkt_size = sizeof(stop); + stop.hdr.src_port = 0; + stop.hdr.dest_port = 0; + stop.hdr.token = index; + stop.hdr.opcode = AFE_PORT_CMD_DEVICE_STOP; + stop.port_id = port_id; + stop.reserved = 0; + + ret = afe_apr_send_pkt(afe, &stop, &port->wait); + if (ret) + dev_err(afe->dev, "AFE close failed %d\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(q6afe_port_stop); + +/** + * q6afe_hdmi_port_prepare() - Prepare hdmi afe port. + * + * @port: Instance of afe port + * @cfg: HDMI configuration for the afe port + * + */ +void q6afe_hdmi_port_prepare(struct q6afe_port *port, + struct q6afe_hdmi_cfg *cfg) +{ + union afe_port_config *pcfg = &port->port_cfg; + + pcfg->hdmi_multi_ch.hdmi_cfg_minor_version = + AFE_API_VERSION_HDMI_CONFIG; + pcfg->hdmi_multi_ch.datatype = cfg->datatype; + pcfg->hdmi_multi_ch.channel_allocation = cfg->channel_allocation; + pcfg->hdmi_multi_ch.sample_rate = cfg->sample_rate; + pcfg->hdmi_multi_ch.bit_width = cfg->bit_width; +} +EXPORT_SYMBOL_GPL(q6afe_hdmi_port_prepare); + +/** + * q6afe_port_start() - Start a afe port + * + * @port: Instance of port to start + * + * Return: Will be an negative on packet size on success. + */ +int q6afe_port_start(struct q6afe_port *port) +{ + return afe_port_start(port, &port->port_cfg); +} +EXPORT_SYMBOL_GPL(q6afe_port_start); + +/** + * q6afe_port_get_from_id() - Get port instance from a port id + * + * @dev: Pointer to afe child device. + * @id: port id + * + * Return: Will be an error pointer on error or a valid afe port + * on success. + */ +struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) +{ + int port_id; + struct q6afev2 *afe = dev_get_drvdata(dev->parent); + struct q6afe_port *port; + int token; + int cfg_type; + + if (!afe) { + dev_err(dev, "Unable to find instance of afe service\n"); + return ERR_PTR(-ENOENT); + } + + token = id; + if (token < 0 || token > AFE_PORT_MAX) { + dev_err(dev, "AFE port token[%d] invalid!\n", token); + return ERR_PTR(-EINVAL); + } + + port_id = port_maps[id].port_id; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + init_waitqueue_head(&port->wait); + + port->token = token; + port->id = port_id; + + port->afe.v2 = afe; + switch (port_id) { + case AFE_PORT_ID_MULTICHAN_HDMI_RX: + cfg_type = AFE_PARAM_ID_HDMI_CONFIG; + break; + default: + dev_err(dev, "Invalid port id 0x%x\n", port_id); + return ERR_PTR(-EINVAL); + } + + port->cfg_type = cfg_type; + + spin_lock(&afe->port_list_lock); + list_add_tail(&port->node, &afe->port_list); + spin_unlock(&afe->port_list_lock); + + return port; + +} +EXPORT_SYMBOL_GPL(q6afe_port_get_from_id); + +/** + * q6afe_port_put() - Release port reference + * + * @port: Instance of port to put + */ +void q6afe_port_put(struct q6afe_port *port) +{ + struct q6afev2 *afe = port->afe.v2; + + spin_lock(&afe->port_list_lock); + list_del(&port->node); + spin_unlock(&afe->port_list_lock); +} +EXPORT_SYMBOL_GPL(q6afe_port_put); + +static int q6afev2_probe(struct apr_device *adev) +{ + struct q6afev2 *afe; + struct device *dev = &adev->dev; + + afe = devm_kzalloc(dev, sizeof(*afe), GFP_KERNEL); + if (!afe) + return -ENOMEM; + + afe->apr = adev; + mutex_init(&afe->afe_cmd_lock); + afe->dev = dev; + INIT_LIST_HEAD(&afe->port_list); + spin_lock_init(&afe->port_list_lock); + + dev_set_drvdata(dev, afe); + + afe->daidev = platform_device_register_data(&adev->dev, "q6afe_dai", + -1, NULL, 0); + return 0; +} + +static int q6afev2_remove(struct apr_device *adev) +{ + struct q6afev2 *afe = dev_get_drvdata(&adev->dev); + + platform_device_unregister(afe->daidev); + + return 0; +} + +static const struct apr_device_id q6asm_id[] = { + {"Q6AFE", APR_DOMAIN_ADSP, APR_SVC_AFE, APR_CLIENT_AUDIO}, + {} +}; + +static struct apr_driver qcom_q6afe_driver = { + .probe = q6afev2_probe, + .remove = q6afev2_remove, + .callback = afe_callback, + .id_table = q6asm_id, + .driver = { + .name = "qcom-q6afe", + }, +}; + +module_apr_driver(qcom_q6afe_driver); +MODULE_DESCRIPTION("Q6 Audio Front End"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h new file mode 100644 index 000000000000..c04541b94a47 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6AFE_H__ +#define __Q6AFE_H__ + +/* Audio Front End (AFE) Ports */ +#define AFE_PORT_HDMI_RX 8 +#define AFE_PORT_MAX 9 + +#define MSM_AFE_PORT_TYPE_RX 0 +#define MSM_AFE_PORT_TYPE_TX 1 +#define AFE_MAX_PORTS AFE_PORT_MAX + +struct q6afe_hdmi_cfg { + u16 datatype; + u16 channel_allocation; + u32 sample_rate; + u16 bit_width; +}; + +struct q6afe_port; + +struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id); +int q6afe_port_start(struct q6afe_port *port); +int q6afe_port_stop(struct q6afe_port *port); +void q6afe_port_put(struct q6afe_port *port); +int q6afe_get_port_id(int index); +void q6afe_hdmi_port_prepare(struct q6afe_port *port, + struct q6afe_hdmi_cfg *cfg); + +#endif /* __Q6AFE_H__ */ From patchwork Tue Dec 5 22:18:02 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 120771 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp6314611qgn; Tue, 5 Dec 2017 14:24:36 -0800 (PST) X-Google-Smtp-Source: AGs4zMYC20IIEIB9uQMMStRv3g/MUpjqqnVidUJlZrRDpDUB7YaB+QM49+hktuvuvsJHkio+cWM6 X-Received: by 10.159.198.70 with SMTP id y6mr20201355plt.334.1512512675923; Tue, 05 Dec 2017 14:24:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512512675; cv=none; d=google.com; s=arc-20160816; b=gppqN15Cimpiw8uC06WvmPBuFvp2QTgO0lILMEYr2839IUlWIEfuTKv7aAMLtsTTHl OWbXT4QRZFVXomuyZgl2NcKB/XGIMxUds2SYki+/ZjKwCcHrOUPeDLpzRLH/Ll6yaXj1 tpyj6evx+t8Nu2TwYhwkRCydLkXcqrH6f1Q2FLt7C0i+I+m04uKs782Liq0zK8qFYqU/ BM3/w7GBdAMv+aIBVZ7mxd72X+XSFOLeRr5TRy+CCgvo89PsxWKGReVacAL2F5KJVdNd Cy4rbYDGUKtzxbTHlLLd26ax5GSMCEBqEB9751ETHTjHzu8VJg+mXn0NvMZqigV7lQ2M adUg== 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=L0wUD3GRQLNMh0w4UmxcKxRo7xNWEnTUcqCGo+ohIFY=; b=xyWFSzPp+zHFc/gTnQ//cWtdKSYNm/LKksL0mj5O+2L2hCfoHezDAciifpN1ENEG8G F2emTKzRT3ySZh9GnXCO+Vz4DQPMQmq27H7KOpiRcv5gw3QyMgB4iD+VdtdStsNym094 z//xbj07DaB/4QWzuaZmjit0ZOtjONe/n20CMMOfoGBg6qPjxt0ucydvGOnyyZe2EXYs w0CImWbNdreIVBwVpGb8z18ao88vQvsi2rfCkhTxHkkTsxOdMUbU/jp22saVyVRGz4Cj HD1oUtmq/IH5yfWGLfXSbgzDG96HCJ0uz/enyrVeJqND+sumNqG1sAMWsoA0S1ctjanU w2Hw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=Wl1n3k1A; 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 m8si797091pfi.343.2017.12.05.14.24.35; Tue, 05 Dec 2017 14:24:35 -0800 (PST) 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=Wl1n3k1A; 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 S1752819AbdLEWYd (ORCPT + 10 others); Tue, 5 Dec 2017 17:24:33 -0500 Received: from mail-wr0-f196.google.com ([209.85.128.196]:41619 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752447AbdLEWU0 (ORCPT ); Tue, 5 Dec 2017 17:20:26 -0500 Received: by mail-wr0-f196.google.com with SMTP id z18so1906371wrb.8 for ; Tue, 05 Dec 2017 14:20:25 -0800 (PST) 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=f/zRsj0OzIeNS0Xd92+bTvAMHKx0Cw4B89d9H8CWiWQ=; b=Wl1n3k1AV2ZfanReB4ymcRyP7hH1jFsNAoSMi0P0tRHVTb7HxzjabvAzldXY/4Wia5 yqoUToEcO4fM4rPVwmLt3gIgZdY+gWaGY+8CW9qR6oruAa42tNWfeaa3J2cGDLj5Uk9u eLnRjr7R9MH16r5t0eNcrv46kD5uKVXLpOvcs= 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=f/zRsj0OzIeNS0Xd92+bTvAMHKx0Cw4B89d9H8CWiWQ=; b=I4xZZ2vZfnSEeiPNve/YYpoiD3SKsRXsjgHG99GI8la2+en8rrQZ6yqrvrgVHnnw3y 9hqKxCS7TZeEef0aD/nAQZRo2nX1IEEhJu/uVhNoqKmQTZKdFFWbcaSy9aEqvjtFXvWA FMG7B8ZXDFmAdWA+rHHHRnlF3eNmoF1Zzp0IIfNa7/KG6bZpD/pEIxVAmHMnx8UIbKP+ qME5U3QSOf9/5wn1FDD6xMlxvyHuhjeiD1IBwjWXATE6QmYrC35YHErbjNC6YMtLvUD3 wrkCXEPqNcSXXck8asJJW6LObegrJuEj4V+d9nYJ8QMlUj433ggJ3UJqmmVvQ5tbzQCV 9PPQ== X-Gm-Message-State: AJaThX6A+L56L7wEmtpF22Lq7hx0PdgDY0BEGLFBdWpvppDO58g7QQMw az8oRVER9OuCMqUTZ1MUT/mKVg== X-Received: by 10.223.176.8 with SMTP id f8mr16189468wra.80.1512512424875; Tue, 05 Dec 2017 14:20:24 -0800 (PST) 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 t138sm1633154wme.16.2017.12.05.14.20.23 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 05 Dec 2017 14:20:24 -0800 (PST) From: srinivas.kandagatla@linaro.org To: broonie@kernel.org, bgoswami@codeaurora.org Cc: alsa-devel@alsa-project.org, tiwai@suse.com, plai@codeaurora.org, kwestfie@codeaurora.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, lkasam@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v2 05/15] ASoC: qcom: qdsp6: Add support to Q6ADM Date: Tue, 5 Dec 2017 22:18:02 +0000 Message-Id: <20171205221812.25641-6-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171205221812.25641-1-srinivas.kandagatla@linaro.org> References: <20171205221812.25641-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 From: Srinivas Kandagatla This patch adds support to q6 ADM (Audio Device Manager) module in q6dsp. ADM performs routing between audio streams and AFE ports. It does Rate matching for streams going to devices driven by different clocks, it handles volume ramping, Mixing with channel and bit-width. ADM creates and destroys dynamic COPP services for device-related audio processing as needed. This patch adds basic support to ADM. Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/Kconfig | 5 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6adm.c | 602 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6adm.h | 24 ++ 4 files changed, 632 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6adm.c create mode 100644 sound/soc/qcom/qdsp6/q6adm.h -- 2.15.0 -- 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 1db92069a6a0..a307880dc992 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -48,9 +48,14 @@ config SND_SOC_QDSP6_AFE tristate default n +config SND_SOC_QDSP6_ADM + tristate + default n + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" select SND_SOC_QDSP6_AFE + select SND_SOC_QDSP6_ADM 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 313e65f571db..052813ea7062 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o +obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c new file mode 100644 index 000000000000..b9f79a198ea4 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -0,0 +1,602 @@ +/* SPDX-License-Identifier: GPL-2.0 +* Copyright (c) 2011-2016, The Linux Foundation +* Copyright (c) 2017, Linaro Limited +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6adm.h" +#include "q6afe.h" +#include "common.h" + +#define ADM_CMD_DEVICE_OPEN_V5 0x00010326 +#define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329 +#define ADM_CMD_DEVICE_CLOSE_V5 0x00010327 +#define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325 + +#define TIMEOUT_MS 1000 +#define RESET_COPP_ID 99 +#define INVALID_COPP_ID 0xFF +/* Definition for a legacy device session. */ +#define ADM_LEGACY_DEVICE_SESSION 0 +#define ADM_MATRIX_ID_AUDIO_RX 0 + +struct copp { + int afe_port; + int copp_idx; + int id; + int cnt; + int topology; + int mode; + int stat; + int rate; + int bit_width; + int channels; + int app_type; + int acdb_id; + wait_queue_head_t wait; + struct list_head node; + struct q6adm *adm; +}; + +struct q6adm { + struct apr_device *apr; + struct device *dev; + unsigned long copp_bitmap[AFE_MAX_PORTS]; + struct list_head copps_list; + spinlock_t copps_list_lock; + int matrix_map_stat; + struct platform_device *routing_dev; + + wait_queue_head_t matrix_map_wait; +}; + +static struct copp *adm_find_copp(struct q6adm *adm, int port_idx, int copp_idx) +{ + struct copp *c; + + spin_lock(&adm->copps_list_lock); + list_for_each_entry(c, &adm->copps_list, node) { + if ((port_idx == c->afe_port) && (copp_idx == c->copp_idx)) { + spin_unlock(&adm->copps_list_lock); + return c; + } + } + + spin_unlock(&adm->copps_list_lock); + return NULL; + +} + +static struct copp *adm_find_matching_copp(struct q6adm *adm, + int port_idx, int topology, + int mode, int rate, + int bit_width, int app_type) +{ + struct copp *c; + + spin_lock(&adm->copps_list_lock); + + list_for_each_entry(c, &adm->copps_list, node) { + if ((port_idx == c->afe_port) && (topology == c->topology) && + (mode == c->mode) && (rate == c->rate) && + (bit_width == c->bit_width) && (app_type == c->app_type)) { + spin_unlock(&adm->copps_list_lock); + return c; + } + } + spin_unlock(&adm->copps_list_lock); + + return NULL; + +} + +static int adm_callback(struct apr_device *adev, struct apr_client_data *data) +{ + uint32_t *payload; + int port_idx, copp_idx; + struct copp *copp; + struct q6adm *adm = dev_get_drvdata(&adev->dev); + + payload = data->payload; + + if (data->payload_size) { + copp_idx = (data->token) & 0XFF; + port_idx = ((data->token) >> 16) & 0xFF; + if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) { + dev_err(&adev->dev, "Invalid port idx %d token %d\n", + port_idx, data->token); + return 0; + } + if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) { + dev_err(&adev->dev, "Invalid copp idx %d token %d\n", + copp_idx, data->token); + return 0; + } + + if (data->opcode == APR_BASIC_RSP_RESULT) { + if (payload[1] != 0) { + dev_err(&adev->dev, "cmd = 0x%x returned error = 0x%x\n", + payload[0], payload[1]); + } + switch (payload[0]) { + case ADM_CMD_DEVICE_OPEN_V5: + case ADM_CMD_DEVICE_CLOSE_V5: + copp = adm_find_copp(adm, port_idx, copp_idx); + if (IS_ERR_OR_NULL(copp)) + return 0; + + copp->stat = payload[1]; + wake_up(&copp->wait); + break; + case ADM_CMD_MATRIX_MAP_ROUTINGS_V5: + adm->matrix_map_stat = payload[1]; + wake_up(&adm->matrix_map_wait); + break; + + default: + dev_err(&adev->dev, "Unknown Cmd: 0x%x\n", + payload[0]); + break; + } + return 0; + } + + switch (data->opcode) { + case ADM_CMDRSP_DEVICE_OPEN_V5:{ + struct adm_cmd_rsp_device_open_v5 { + u32 status; + u16 copp_id; + u16 reserved; + } __packed * open = data->payload; + + open = data->payload; + copp = adm_find_copp(adm, port_idx, copp_idx); + if (IS_ERR_OR_NULL(copp)) + return 0; + + if (open->copp_id == INVALID_COPP_ID) { + dev_err(&adev->dev, "Invalid coppid rxed %d\n", + open->copp_id); + copp->stat = ADSP_EBADPARAM; + wake_up(&copp->wait); + break; + } + copp->stat = payload[0]; + copp->id = open->copp_id; + pr_debug("%s: coppid rxed=%d\n", __func__, + open->copp_id); + wake_up(&copp->wait); + + } + break; + default: + dev_err(&adev->dev, "Unknown cmd:0x%x\n", + data->opcode); + break; + } + } + return 0; +} + +static struct copp *adm_alloc_copp(struct q6adm *adm, int port_idx) +{ + struct copp *c; + int idx; + + idx = find_first_zero_bit(&adm->copp_bitmap[port_idx], + MAX_COPPS_PER_PORT); + + if (idx > MAX_COPPS_PER_PORT) + return ERR_PTR(-EBUSY); + + set_bit(idx, &adm->copp_bitmap[port_idx]); + + c = devm_kzalloc(adm->dev, sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + c->copp_idx = idx; + c->afe_port = port_idx; + c->adm = adm; + + init_waitqueue_head(&c->wait); + + spin_lock(&adm->copps_list_lock); + list_add_tail(&c->node, &adm->copps_list); + spin_unlock(&adm->copps_list_lock); + + return c; +} + +static void adm_free_copp(struct q6adm *adm, struct copp *c, int port_idx) +{ + clear_bit(c->copp_idx, &adm->copp_bitmap[port_idx]); + spin_lock(&adm->copps_list_lock); + list_del(&c->node); + spin_unlock(&adm->copps_list_lock); +} +/** + * q6adm_open() - open adm to get hold of free copp + * + * @dev: Pointer to adm child device. + * @port_id: port id + * @path: playback or capture path. + * @rate: rate at which copp is required. + * @channel_mode: channel mode + * @topology: adm topology id + * @perf_mode: performace mode. + * @bit_width: audio sample bit width + * @app_type: Application type. + * @acdb_id: ACDB id + * + * Return: Will be an negative on error or a valid copp index on success. + */ +int q6adm_open(struct device *dev, int port_id, int path, int rate, + int channel_mode, int topology, int perf_mode, + uint16_t bit_width, int app_type, int acdb_id) +{ + struct adm_cmd_device_open_v5 { + struct apr_hdr hdr; + u16 flags; + u16 mode_of_operation; + u16 endpoint_id_1; + u16 endpoint_id_2; + u32 topology_id; + u16 dev_num_channel; + u16 bit_width; + u32 sample_rate; + u8 dev_channel_mapping[8]; + } __packed open; + int ret = 0; + int port_idx, flags; + int tmp_port = q6afe_get_port_id(port_id); + struct copp *copp; + struct q6adm *adm = dev_get_drvdata(dev->parent); + + port_idx = port_id; + if (port_idx < 0) { + dev_err(dev, "Invalid port_id 0x%x\n", port_id); + return -EINVAL; + } + + flags = ADM_LEGACY_DEVICE_SESSION; + copp = adm_find_matching_copp(adm, port_idx, topology, perf_mode, + rate, bit_width, app_type); + + if (!copp) { + copp = adm_alloc_copp(adm, port_idx); + if (IS_ERR_OR_NULL(copp)) + return PTR_ERR(copp); + + copp->cnt = 0; + copp->topology = topology; + copp->mode = perf_mode; + copp->rate = rate; + copp->channels = channel_mode; + copp->bit_width = bit_width; + copp->app_type = app_type; + } + + /* Create a COPP if port id are not enabled */ + if (copp->cnt == 0) { + + open.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + open.hdr.pkt_size = sizeof(open); + open.hdr.src_svc = APR_SVC_ADM; + open.hdr.src_domain = APR_DOMAIN_APPS; + open.hdr.src_port = tmp_port; + open.hdr.dest_svc = APR_SVC_ADM; + open.hdr.dest_domain = APR_DOMAIN_ADSP; + open.hdr.dest_port = tmp_port; + open.hdr.token = port_idx << 16 | copp->copp_idx; + open.hdr.opcode = ADM_CMD_DEVICE_OPEN_V5; + open.flags = flags; + open.mode_of_operation = path; + open.endpoint_id_1 = tmp_port; + open.topology_id = topology; + open.dev_num_channel = channel_mode & 0x00FF; + open.bit_width = bit_width; + open.sample_rate = rate; + + ret = q6dsp_map_channels(&open.dev_channel_mapping[0], + channel_mode); + + if (ret) + return ret; + + copp->stat = -1; + ret = apr_send_pkt(adm->apr, (uint32_t *)&open); + if (ret < 0) { + dev_err(dev, "port_id: 0x%x for[0x%x] failed %d\n", + tmp_port, port_id, ret); + return -EINVAL; + } + /* Wait for the callback with copp id */ + ret = + wait_event_timeout(copp->wait, copp->stat >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + dev_err(dev, "ADM timedout port_id: 0x%x for [0x%x]\n", + tmp_port, port_id); + return -EINVAL; + } else if (copp->stat > 0) { + dev_err(dev, "DSP returned error[%s]\n", + adsp_err_get_err_str(copp->stat)); + return adsp_err_get_lnx_err_code(copp->stat); + } + } + copp->cnt++; + return copp->copp_idx; +} +EXPORT_SYMBOL_GPL(q6adm_open); +/** + * q6adm_matrix_map() - Map asm streams and afe ports using payload + * + * @dev: Pointer to adm child device. + * @path: playback or capture path. + * @payload_map: map between session id and afe ports. + * @perf_mode: Performace mode. + * + * Return: Will be an negative on error or a zero on success. + */ +int q6adm_matrix_map(struct device *dev, int path, + struct route_payload payload_map, int perf_mode) +{ + struct adm_cmd_matrix_map_routings_v5 { + struct apr_hdr hdr; + u32 matrix_id; + u32 num_sessions; + } __packed * route; + + struct adm_session_map_node_v5 { + u16 session_id; + u16 num_copps; + } __packed * node; + struct q6adm *adm = dev_get_drvdata(dev->parent); + uint16_t *copps_list; + int cmd_size = 0; + int ret = 0, i = 0; + void *payload = NULL; + void *matrix_map = NULL; + int port_idx, copp_idx; + struct copp *copp; + + /* Assumes port_ids have already been validated during adm_open */ + cmd_size = (sizeof(*route) + + sizeof(*node) + + (sizeof(uint32_t) * payload_map.num_copps)); + matrix_map = kzalloc(cmd_size, GFP_KERNEL); + if (!matrix_map) + return -ENOMEM; + + route = (struct adm_cmd_matrix_map_routings_v5 *)matrix_map; + route->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + route->hdr.pkt_size = cmd_size; + route->hdr.src_svc = 0; + route->hdr.src_domain = APR_DOMAIN_APPS; + route->hdr.src_port = 0; /* Ignored */ + route->hdr.dest_svc = APR_SVC_ADM; + route->hdr.dest_domain = APR_DOMAIN_ADSP; + route->hdr.dest_port = 0; /* Ignored */ + route->hdr.token = 0; + route->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5; + route->num_sessions = 1; + + switch (path) { + case ADM_PATH_PLAYBACK: + route->matrix_id = ADM_MATRIX_ID_AUDIO_RX; + break; + default: + dev_err(dev, "Wrong path set[%d]\n", path); + + break; + } + + payload = ((u8 *) matrix_map + sizeof(*route)); + node = (struct adm_session_map_node_v5 *)payload; + + node->session_id = payload_map.session_id; + node->num_copps = payload_map.num_copps; + payload = (u8 *) node + sizeof(*node); + copps_list = (uint16_t *) payload; + + for (i = 0; i < payload_map.num_copps; i++) { + port_idx = payload_map.port_id[i]; + if (port_idx < 0) { + dev_err(dev, "Invalid port_id 0x%x\n", + payload_map.port_id[i]); + return -EINVAL; + } + copp_idx = payload_map.copp_idx[i]; + + copp = adm_find_copp(adm, port_idx, copp_idx); + if (IS_ERR_OR_NULL(copp)) + return -EINVAL; + + copps_list[i] = copp->id; + } + + adm->matrix_map_stat = -1; + + ret = apr_send_pkt(adm->apr, (uint32_t *) matrix_map); + if (ret < 0) { + dev_err(dev, "routing for syream %d failed ret %d\n", + payload_map.session_id, ret); + ret = -EINVAL; + goto fail_cmd; + } + ret = wait_event_timeout(adm->matrix_map_wait, + adm->matrix_map_stat >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + dev_err(dev, "routing for syream %d failed\n", + payload_map.session_id); + ret = -EINVAL; + goto fail_cmd; + } else if (adm->matrix_map_stat > 0) { + dev_err(dev, "DSP returned error[%s]\n", + adsp_err_get_err_str(adm->matrix_map_stat)); + ret = adsp_err_get_lnx_err_code(adm->matrix_map_stat); + goto fail_cmd; + } + +fail_cmd: + kfree(matrix_map); + return ret; +} +EXPORT_SYMBOL_GPL(q6adm_matrix_map); + +static void adm_reset_copp(struct copp *c) +{ + c->id = RESET_COPP_ID; + c->cnt = 0; + c->topology = 0; + c->mode = 0; + c->stat = -1; + c->rate = 0; + c->channels = 0; + c->bit_width = 0; + c->app_type = 0; +} +/** + * q6adm_close() - Close adm copp + * + * @dev: Pointer to adm child device. + * @port_id: afe port id. + * @perf_mode: perf_mode mode + * @copp_idx: copp index to close + * + * Return: Will be an negative on error or a zero on success. + */ +int q6adm_close(struct device *dev, int port_id, int perf_mode, int copp_idx) +{ + struct apr_hdr close; + struct copp *copp; + + int ret = 0, port_idx; + int copp_id = RESET_COPP_ID; + struct q6adm *adm = dev_get_drvdata(dev->parent); + + port_idx = port_id; + if (port_idx < 0) { + dev_err(dev, "Invalid port_id 0x%x\n", port_id); + return -EINVAL; + } + + if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) { + dev_err(dev, "Invalid copp idx: %d\n", copp_idx); + return -EINVAL; + } + + copp = adm_find_copp(adm, port_id, copp_idx); + if (IS_ERR_OR_NULL(copp)) + return -EINVAL; + + copp->cnt--; + if (!copp->cnt) { + copp_id = copp->id; + + close.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + close.pkt_size = sizeof(close); + close.src_svc = APR_SVC_ADM; + close.src_domain = APR_DOMAIN_APPS; + close.src_port = port_id; + close.dest_svc = APR_SVC_ADM; + close.dest_domain = APR_DOMAIN_ADSP; + close.dest_port = copp_id; + close.token = port_idx << 16 | copp_idx; + close.opcode = ADM_CMD_DEVICE_CLOSE_V5; + + ret = apr_send_pkt(adm->apr, (uint32_t *) &close); + if (ret < 0) { + dev_err(dev, "ADM close failed %d\n", ret); + return -EINVAL; + } + + ret = wait_event_timeout(copp->wait, copp->stat >= 0, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + dev_err(dev, "ADM cmd Route timedout for port 0x%x\n", + port_id); + return -EINVAL; + } else if (copp->stat > 0) { + dev_err(dev, "DSP returned error[%s]\n", + adsp_err_get_err_str(copp->stat)); + return adsp_err_get_lnx_err_code(copp->stat); + } + + adm_reset_copp(copp); + adm_free_copp(adm, copp, port_id); + } + + return 0; +} +EXPORT_SYMBOL_GPL(q6adm_close); + +static int q6adm_probe(struct apr_device *adev) +{ + struct q6adm *adm; + + adm = devm_kzalloc(&adev->dev, sizeof(*adm), GFP_KERNEL); + if (!adm) + return -ENOMEM; + + adm->apr = adev; + dev_set_drvdata(&adev->dev, adm); + adm->dev = &adev->dev; + adm->matrix_map_stat = 0; + init_waitqueue_head(&adm->matrix_map_wait); + + INIT_LIST_HEAD(&adm->copps_list); + spin_lock_init(&adm->copps_list_lock); + + adm->routing_dev = platform_device_register_data(&adev->dev, + "q6routing", + -1, NULL, 0); + + + return 0; +} + +static int q6adm_exit(struct apr_device *adev) +{ + struct q6adm *adm = dev_get_drvdata(&adev->dev); + + platform_device_unregister(adm->routing_dev); + + return 0; +} + +static const struct apr_device_id adm_id[] = { + {"Q6ADM", APR_DOMAIN_ADSP, APR_SVC_ADM, APR_CLIENT_AUDIO}, + {} +}; + +static struct apr_driver qcom_q6adm_driver = { + .probe = q6adm_probe, + .remove = q6adm_exit, + .callback = adm_callback, + .id_table = adm_id, + .driver = { + .name = "qcom-q6adm", + }, +}; + +module_apr_driver(qcom_q6adm_driver); +MODULE_DESCRIPTION("Q6 Audio Device Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6adm.h b/sound/soc/qcom/qdsp6/q6adm.h new file mode 100644 index 000000000000..aa7b3ba4360b --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6adm.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6_ADM_V2_H__ +#define __Q6_ADM_V2_H__ + +#define ADM_PATH_PLAYBACK 0x1 +#define MAX_COPPS_PER_PORT 8 +#define NULL_COPP_TOPOLOGY 0x00010312 + +/* multiple copp per stream. */ +struct route_payload { + int num_copps; + int session_id; + int copp_idx[MAX_COPPS_PER_PORT]; + int port_id[MAX_COPPS_PER_PORT]; +}; + +int q6adm_open(struct device *dev, int port_id, int path, int rate, + int channel_mode, int topology, int perf_mode, + uint16_t bit_width, int app_type, int acdb_id); +int q6adm_close(struct device *dev, int port, int topology, int perf_mode); +int q6adm_matrix_map(struct device *dev, int path, + struct route_payload payload_map, int perf_mode); + +#endif /* __Q6_ADM_V2_H__ */ From patchwork Tue Dec 5 22:18:03 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 120770 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp6314577qgn; Tue, 5 Dec 2017 14:24:34 -0800 (PST) X-Google-Smtp-Source: AGs4zMa/mzb1Eln/KXpQkX7Lu2oEf6uu7pZgpGphkf4Jl97tCCgGSD7W3oQDephVfCYEzHdXkHL0 X-Received: by 10.99.55.92 with SMTP id g28mr19368319pgn.293.1512512674276; Tue, 05 Dec 2017 14:24:34 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512512674; cv=none; d=google.com; s=arc-20160816; b=DrJBLV6pzmaqaqUcK61PLXwF55dQVijJ9LRU+ag0tOOHke5NZlWwq7/BPflEvvF1Qk 6rcH7z4LDXjyGDpVdUoWkqgi5wbKOq2+w458ziK2n2oPfr2xY/iFvXmcLtzwcnYa8mg8 qKm89U0TPJD33V+svCfjY+rpup8tUb4eS69CZMqCFZz7lVkQJDhkLJ/N1JFFHlRbHhXL n0kqar/ETf0zAnkAAe1rhiJXKR+dYTIH3rejbJv1v1JNPq6gCXMAyyoz/uXO4kOCSHt0 uoB6SPFmMaBSUwYnie8NvMrUcslpF9FH5H+Am7uf4LVxTj9lBzRrLwSBBlC5t8yuZ+1m GEaQ== 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=tAxYC3cXQPrm1YcwsAy1bsUKpTEsDemMkDHSVQFs+ok=; b=MzrLh40jwzXPnJWthrBtOfVgVGRbyZInz/R1OTxdc0h5ybuX1u+vGXIgNWGtFotomF gLZcIMn9OCXT38wn8TEV2frLCrAm95Gl4bBvEqhHIDyxbI8n/CvTvyhkETXKh0Ki+ql7 Uv62nNYLLR6Lj1yxthhmL72CCnMrnQvBugntOrpfXOT+TzKgTsUMMOvVUbRIu40s/HTc LKZ5ym1Dvsgm3gbnSLVR4EMJctwQEJ5RCiverPdJqq+SNrCbRJubHa6PEcVuXMfXG23n RRBGY2Gp9voOyGVuDxhFBzZoB/DP3epyjNdzeVRHFx6eTGDdOOAOJMXWdsbsHvR5iVC7 sQWg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=bAUbHUnf; 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 m8si797091pfi.343.2017.12.05.14.24.34; Tue, 05 Dec 2017 14:24:34 -0800 (PST) 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=bAUbHUnf; 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 S1752143AbdLEWYc (ORCPT + 10 others); Tue, 5 Dec 2017 17:24:32 -0500 Received: from mail-wr0-f194.google.com ([209.85.128.194]:46941 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752470AbdLEWU1 (ORCPT ); Tue, 5 Dec 2017 17:20:27 -0500 Received: by mail-wr0-f194.google.com with SMTP id x49so1902158wrb.13 for ; Tue, 05 Dec 2017 14:20:26 -0800 (PST) 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=EaGdKQ75qLPmdkyoqpfr5BGU14ZHnd8D48G7JV0Vh08=; b=bAUbHUnfEv6NWPkdMG+S4BeFwJnGxlpBE09P5Zll3yiy1zEKEjcOYzgdVrkX1kP2Rz QnUaB0uP+e+2ZZDDzyuezt3mvTpVifrN+AnmfOhFgF5RVG/84A3jhat85GQDVxEP2YTj jr9DpjFcj2InbNT/VAVMSwy7WdlCkeUrxbiN8= 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=EaGdKQ75qLPmdkyoqpfr5BGU14ZHnd8D48G7JV0Vh08=; b=ng2EUggF69tssMIirpGmSjS7RzgHScvOM0nWOntamsClAjSa5EousT3ghtgoqp8ykS aKfrzNJ0288Hz0ChZ5ObdCtDuS4OMgI6+XHbiLwLXQQJ2SWmKobvvqJL+Ww+IL1N+etK zy7jgJLPu/eQqxlTBB5sRT/zl005zJRSZg8EbGvQZbzi3bC4keIEaQropJTvAqQQN9xb ypy2YWYXFCuVo0dIusmNB+sP1btpEVufu9PmzhDI8mWyz3OBvUzZAic2KJMkY6t2F92R DqnKZwCGOAXtIMtzr/l4Hef+BTcYxoAcvroy7rUs91WwoBAY8A3ear7KHKLeD42WQoks a69A== X-Gm-Message-State: AJaThX62TfjG0sZTXHRS2JHJXBJRGfG8PFJvtb7FBHqOkIjjpVAqeheD x88Y43z/f+4VWDC905JRHJSnPQ== X-Received: by 10.223.152.1 with SMTP id v1mr19620391wrb.234.1512512425875; Tue, 05 Dec 2017 14:20:25 -0800 (PST) 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 t138sm1633154wme.16.2017.12.05.14.20.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 05 Dec 2017 14:20:25 -0800 (PST) From: srinivas.kandagatla@linaro.org To: broonie@kernel.org, bgoswami@codeaurora.org Cc: alsa-devel@alsa-project.org, tiwai@suse.com, plai@codeaurora.org, kwestfie@codeaurora.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, lkasam@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v2 06/15] ASoC: qcom: qdsp6: Add support to Q6ASM Date: Tue, 5 Dec 2017 22:18:03 +0000 Message-Id: <20171205221812.25641-7-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171205221812.25641-1-srinivas.kandagatla@linaro.org> References: <20171205221812.25641-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 From: Srinivas Kandagatla 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 --- sound/soc/qcom/Kconfig | 5 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6asm.c | 250 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6asm.h | 14 +++ 4 files changed, 270 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6asm.c create mode 100644 sound/soc/qcom/qdsp6/q6asm.h -- 2.15.0 -- 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 a307880dc992..7ebdb879a8a3 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -52,10 +52,15 @@ config SND_SOC_QDSP6_ADM tristate default n +config SND_SOC_QDSP6_ASM + tristate + default n + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" 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 052813ea7062..49dd3ccab27b 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,2 +1,3 @@ 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..9cc583afef4d --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -0,0 +1,250 @@ +/* SPDX-License-Identifier: GPL-2.0 +* Copyright (c) 2011-2016, The Linux Foundation +* Copyright (c) 2017, Linaro Limited +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6asm.h" +#include "common.h" + +#define TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ +#define SYNC_IO_MODE 0x0001 +#define ASYNC_IO_MODE 0x0002 + +struct audio_client { + int session; + app_cb cb; + int cmd_state; + void *priv; + uint32_t io_mode; + uint64_t time_stamp; + struct apr_device *adev; + struct mutex cmd_lock; + wait_queue_head_t cmd_wait; + int perf_mode; + int stream_id; + struct device *dev; +}; + +struct q6asm { + struct apr_device *adev; + int mem_state; + struct device *dev; + wait_queue_head_t mem_wait; + struct mutex session_lock; + struct platform_device *pcmdev; + struct audio_client *session[MAX_SESSIONS + 1]; +}; + +static int q6asm_session_alloc(struct audio_client *ac, struct q6asm *a) +{ + int n = -EINVAL; + + mutex_lock(&a->session_lock); + for (n = 1; n <= MAX_SESSIONS; n++) { + if (!a->session[n]) { + a->session[n] = ac; + break; + } + } + mutex_unlock(&a->session_lock); + + return n; +} + +static bool q6asm_is_valid_audio_client(struct audio_client *ac) +{ + struct q6asm *a = dev_get_drvdata(ac->dev->parent); + int n; + + for (n = 1; n <= MAX_SESSIONS; n++) { + if (a->session[n] == ac) + return 1; + } + + return 0; +} + +static void q6asm_session_free(struct audio_client *ac) +{ + struct q6asm *a = dev_get_drvdata(ac->dev->parent); + + if (!a) + return; + + mutex_lock(&a->session_lock); + a->session[ac->session] = 0; + ac->session = 0; + ac->perf_mode = LEGACY_PCM_MODE; + mutex_unlock(&a->session_lock); +} + +/** + * q6asm_audio_client_free() - Freee allocated audio client + * + * @ac: audio client to free + */ +void q6asm_audio_client_free(struct audio_client *ac) +{ + q6asm_session_free(ac); + kfree(ac); +} +EXPORT_SYMBOL_GPL(q6asm_audio_client_free); + +static struct audio_client *q6asm_get_audio_client(struct q6asm *a, + int session_id) +{ + if ((session_id <= 0) || (session_id > MAX_SESSIONS)) { + dev_err(a->dev, "invalid session: %d\n", session_id); + goto err; + } + + if (!a->session[session_id]) { + dev_err(a->dev, "session not active: %d\n", session_id); + goto err; + } + return a->session[session_id]; +err: + return NULL; +} + +static int q6asm_srvc_callback(struct apr_device *adev, struct apr_client_data *data) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + struct audio_client *ac = NULL; + uint32_t sid = 0; + uint32_t *payload; + + if (!data) { + dev_err(&adev->dev, "%s: Invalid CB\n", __func__); + return 0; + } + + payload = data->payload; + sid = (data->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(data->opcode, data->token, data->payload, ac->priv); + return 0; +} + +/** + * q6asm_get_session_id() - get session id for audio client + * + * @ac: 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. + * + * 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, + app_cb cb, void *priv) +{ + struct q6asm *a = dev_get_drvdata(dev->parent); + struct audio_client *ac; + int n; + + ac = kzalloc(sizeof(struct audio_client), GFP_KERNEL); + if (!ac) + return NULL; + + n = q6asm_session_alloc(ac, a); + if (n <= 0) { + dev_err(dev, "ASM Session alloc fail n=%d\n", n); + kfree(ac); + return NULL; + } + + ac->session = n; + ac->cb = cb; + ac->dev = dev; + ac->priv = priv; + ac->io_mode = SYNC_IO_MODE; + ac->perf_mode = LEGACY_PCM_MODE; + /* DSP expects stream id from 1 */ + ac->stream_id = 1; + ac->adev = a->adev; + + init_waitqueue_head(&ac->cmd_wait); + mutex_init(&ac->cmd_lock); + ac->cmd_state = 0; + + return ac; +} +EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); + + +static int q6asm_probe(struct apr_device *adev) +{ + struct q6asm *q6asm; + + q6asm = devm_kzalloc(&adev->dev, sizeof(*q6asm), GFP_KERNEL); + if (!q6asm) + return -ENOMEM; + + q6asm->dev = &adev->dev; + q6asm->adev = adev; + q6asm->mem_state = 0; + init_waitqueue_head(&q6asm->mem_wait); + mutex_init(&q6asm->session_lock); + dev_set_drvdata(&adev->dev, q6asm); + + q6asm->pcmdev = platform_device_register_data(&adev->dev, + "q6asm_dai", -1, NULL, 0); + + return 0; +} + +static int q6asm_remove(struct apr_device *adev) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + + platform_device_unregister(q6asm->pcmdev); + + return 0; +} + +static const struct apr_device_id q6asm_id[] = { + {"Q6ASM", APR_DOMAIN_ADSP, APR_SVC_ASM, APR_CLIENT_AUDIO}, + {} +}; + +static struct apr_driver qcom_q6asm_driver = { + .probe = q6asm_probe, + .remove = q6asm_remove, + .callback = q6asm_srvc_callback, + .id_table = q6asm_id, + .driver = { + .name = "qcom-q6asm", + }, +}; + +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..7a8a9039fd89 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6_ASM_H__ +#define __Q6_ASM_H__ + +#define MAX_SESSIONS 16 + +typedef void (*app_cb) (uint32_t opcode, uint32_t token, + uint32_t *payload, void *priv); +struct audio_client; +struct audio_client *q6asm_audio_client_alloc(struct device *dev, + app_cb cb, void *priv); +void q6asm_audio_client_free(struct audio_client *ac); +int q6asm_get_session_id(struct audio_client *ac); +#endif /* __Q6_ASM_H__ */ From patchwork Tue Dec 5 22:18:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 120767 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp6313448qgn; Tue, 5 Dec 2017 14:23:06 -0800 (PST) X-Google-Smtp-Source: AGs4zMajT+9OOH73oY2lH0pEx3/5ZBT+tWQwhmOtDC94kQ/41kxPl4eJ17RBxGE/LAlRIfzUEYOo X-Received: by 10.84.215.146 with SMTP id l18mr19703636pli.451.1512512586051; Tue, 05 Dec 2017 14:23:06 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512512586; cv=none; d=google.com; s=arc-20160816; b=d+rtbEElkdsInapeP07wXxcHjyxPdpRg1wsVg3faRXUVB/eMVH39d8hNbcvghRNrmw GnxG1BIOoAQl2Po6+tF2nRhKZEcpKCyWUJ+XEy/QLbI/LGUUWaJtAkOsnAB4KY6fSODm A7Tbiag6RqMyGLu9rD9YcRajwb0Rv5odB0HiL+QjFb/pu7h5bCruxkFTlZRsaNr6xlvk 2wUrcQxNEYck8pzs9/i2pfgwW/sJx/aApjZeBu+4lKgV/jfXQRAfsvEImrcPTjJXCqLc y86ohfs4nyDDi/ToYrPpLwtmM72U/jAZjdE1LPZ1XMP0Fm83IWiBS0Fg1tSwdsPK8Rxo DkXQ== 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=4U6sPacbpCKTZG/bErM8IDVbkcvYgiQnLu3UgSEgOfY=; b=WzLKrr46LLCWXb6/FIJEKbrvKnA70TWlWhm51AJ9kOBEQFjc0tYtXv2JMpk3OK7V5K rbxKc4GkRXNExLhUEZ4NoqSV+NruIQKjw4SZwlQ7YjHw9usJrCvlBLrWaK2+wYHCg8x9 1zACbS+5BEzEKFC8MFcz0rX3vxZKVA9o6faQVGSODfc3BVNKwsWar1HGkW4SHgHkE9bT 4zCyLTv5zpo4xYR/ymFuaUoipE4mxX2YycynZKtsytbA4oYOwkDZ+73XOzkSreoo0yyl rBZs2dlj4HPzm2WFV69RR6MiwaAXzLxOXHLqPyRDAmRZqa9cOB+sN+51h/7b+3to4uhO gRgA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=QcHfQrFl; 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 u13si723136pgc.615.2017.12.05.14.23.05; Tue, 05 Dec 2017 14:23:06 -0800 (PST) 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=QcHfQrFl; 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 S1752668AbdLEWXC (ORCPT + 10 others); Tue, 5 Dec 2017 17:23:02 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:39627 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752062AbdLEWUc (ORCPT ); Tue, 5 Dec 2017 17:20:32 -0500 Received: by mail-wm0-f65.google.com with SMTP id i11so3941575wmf.4 for ; Tue, 05 Dec 2017 14:20:32 -0800 (PST) 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=/6OvCdALqvPvLxUhpXcW0GuutrQiSpZnYZoud1azjzg=; b=QcHfQrFldrN6RsuDNszMYRjwDZ8HEs/8pAmLxXwMy/OvF5Wnd7QUI9DAS/riZcudDL UsgEbAjnlfNVq0SSb93F4FjJdZRu0q4trdLoR1uYlKhTFcSqUUwssvy8hFmRDPG1ryWZ wiV9Jz9fzpmO4qaRwet8qeYjhtDIwiVzEKsJc= 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=/6OvCdALqvPvLxUhpXcW0GuutrQiSpZnYZoud1azjzg=; b=Pckq1oYfLACjShtiaNszmfCq45/XQxNTHmogW7b5Sqx5DEnx/p7SGq4zvkIZ9r7/DI a2PvwHkRWK/d75sDjfJ04/wBFMeErmYKdHEcfzTZkm7HHNrrn/ZLr34fWzpCC6xNJFYV auDfaLku9kh4bBOcZh6TVTaic3uMI/O4VjkTX6WwBPa+bmbY62lLPMiaTckokMUhp5D0 u3bI2Pa4qY4TF0SZQ8rz26tz1xVZ62xG/oW4yxXCwJPthGbTXaIqdIOpSxm1eS9Xyky2 IO5E76E6ZtVS2JVgErjSfaqLBoud5L1KWLYQgMFsK0I4SISEudVIDszqAIrlnaLzDHsZ jkvw== X-Gm-Message-State: AKGB3mKbMc64zD4KYV0C2m2wlIVJWI9nR+UeOM+ZQQpP3zSvEatxrfn5 VkNffGkTvs+Gn2sXN07Y4Rx6jA== X-Received: by 10.28.88.65 with SMTP id m62mr12581419wmb.111.1512512431245; Tue, 05 Dec 2017 14:20:31 -0800 (PST) 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 t138sm1633154wme.16.2017.12.05.14.20.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 05 Dec 2017 14:20:30 -0800 (PST) From: srinivas.kandagatla@linaro.org To: broonie@kernel.org, bgoswami@codeaurora.org Cc: alsa-devel@alsa-project.org, tiwai@suse.com, plai@codeaurora.org, kwestfie@codeaurora.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, lkasam@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v2 11/15] ASoC: qcom: qdsp6: Add support to q6afe dai driver Date: Tue, 5 Dec 2017 22:18:08 +0000 Message-Id: <20171205221812.25641-12-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171205221812.25641-1-srinivas.kandagatla@linaro.org> References: <20171205221812.25641-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 From: Srinivas Kandagatla This patch adds support to q6afe backend dais driver. Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/Kconfig | 5 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6afe-dai.c | 241 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6afe-dai.c -- 2.15.0 -- 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 dd8fb0cde614..003ce182691c 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -64,6 +64,10 @@ config SND_SOC_QDSP6_ROUTING tristate default n +config SND_SOC_QDSP6_AFE_DAI + tristate + default n + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" select SND_SOC_QDSP6_AFE @@ -71,6 +75,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_ASM select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_ROUTING + select SND_SOC_QDSP6_AFE_DAI 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 c1ad060a2341..bd8bd02bf09e 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o +obj-$(CONFIG_SND_SOC_QDSP6_AFE_DAI) += q6afe-dai.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..e9865c684bcb --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -0,0 +1,241 @@ +/* SPDX-License-Identifier: GPL-2.0 +* Copyright (c) 2011-2016, The Linux Foundation +* Copyright (c) 2017, Linaro Limited +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6afe.h" + +struct q6hdmi_dai_data { + struct q6afe_port *port; + struct q6afe_hdmi_cfg port_config; + bool is_port_started; +}; + +static int q6hdmi_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct q6hdmi_dai_data *dai_data = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + + dai_data->port_config.datatype = value; + + return 0; +} + +static int q6hdmi_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct q6hdmi_dai_data *dai_data = kcontrol->private_data; + + ucontrol->value.integer.value[0] = + dai_data->port_config.datatype; + + return 0; +} + +static const char * const hdmi_format[] = { + "LPCM", + "Compr" +}; + +static const struct soc_enum hdmi_config_enum[] = { + SOC_ENUM_SINGLE_EXT(2, hdmi_format), +}; + +static const struct snd_kcontrol_new hdmi_config_controls[] = { + SOC_ENUM_EXT("HDMI RX Format", hdmi_config_enum[0], + q6hdmi_format_get, + q6hdmi_format_put), +}; + +static int q6hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev); + int channels = params_channels(params); + + dai_data->port_config.sample_rate = params_rate(params); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dai_data->port_config.bit_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dai_data->port_config.bit_width = 24; + break; + } + + /*refer to HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4*/ + switch (channels) { + case 2: + dai_data->port_config.channel_allocation = 0; + break; + case 3: + dai_data->port_config.channel_allocation = 0x02; + break; + case 4: + dai_data->port_config.channel_allocation = 0x06; + break; + case 5: + dai_data->port_config.channel_allocation = 0x0A; + break; + case 6: + dai_data->port_config.channel_allocation = 0x0B; + break; + case 7: + dai_data->port_config.channel_allocation = 0x12; + break; + case 8: + dai_data->port_config.channel_allocation = 0x13; + break; + default: + dev_err(dai->dev, "invalid Channels = %u\n", channels); + return -EINVAL; + } + + return 0; +} + +static int q6hdmi_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev); + + dai_data->is_port_started = false; + + return 0; +} + +static void q6hdmi_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + rc = q6afe_port_stop(dai_data->port); + if (rc < 0) + dev_err(dai->dev, "fail to close AFE port\n"); + + dai_data->is_port_started = false; + +} + +static int q6hdmi_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6hdmi_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + if (dai_data->is_port_started) { + /* stop the port and restart with new port config */ + rc = q6afe_port_stop(dai_data->port); + if (rc < 0) { + dev_err(dai->dev, "fail to close AFE port\n"); + return rc; + } + } + + q6afe_hdmi_port_prepare(dai_data->port, &dai_data->port_config); + rc = q6afe_port_start(dai_data->port); + if (rc < 0) { + dev_err(dai->dev, "fail to start AFE port %x\n", dai->id); + return rc; + } + dai_data->is_port_started = true; + + return 0; +} + +static const struct snd_soc_dapm_route hdmi_dapm_routes[] = { + {"HDMI Playback", NULL, "HDMI"}, +}; + +static struct snd_soc_dai_ops q6hdmi_ops = { + .prepare = q6hdmi_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6hdmi_shutdown, + .startup = q6hdmi_startup, +}; + +static struct snd_soc_dai_driver q6afe_dai_hdmi_rx = { + .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 = AFE_PORT_HDMI_RX, + .name = "HDMI", +}; + +static const struct snd_soc_dapm_widget hdmi_dapm_widgets[] = { + SND_SOC_DAPM_AIF_OUT("HDMI", "HDMI Playback", 0, 0, 0, 0), + SND_SOC_DAPM_OUTPUT("HDMI-RX"), +}; + +static const struct snd_soc_component_driver msm_dai_hdmi_q6_component = { + .name = "msm-dai-q6-hdmi", + .dapm_widgets = hdmi_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(hdmi_dapm_widgets), + .controls = hdmi_config_controls, + .num_controls = ARRAY_SIZE(hdmi_config_controls), + .dapm_routes = hdmi_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(hdmi_dapm_routes), +}; + +static int q6afe_dai_dev_probe(struct platform_device *pdev) +{ + struct q6hdmi_dai_data *dai_data; + int rc = 0; + struct q6afe_port *port; + + dai_data = devm_kzalloc(&pdev->dev, sizeof(*dai_data), GFP_KERNEL); + if (!dai_data) + rc = -ENOMEM; + + port = q6afe_port_get_from_id(&pdev->dev, AFE_PORT_HDMI_RX); + if (IS_ERR(port)) { + dev_err(&pdev->dev, "Unable to get afe port\n"); + return -EPROBE_DEFER; + } + dai_data->port = port; + dev_set_drvdata(&pdev->dev, dai_data); + + return devm_snd_soc_register_component(&pdev->dev, + &msm_dai_hdmi_q6_component, + &q6afe_dai_hdmi_rx, 1); +} + +static int q6afe_dai_dev_remove(struct platform_device *pdev) +{ + struct q6hdmi_dai_data *dai_data = dev_get_drvdata(&pdev->dev); + + q6afe_port_put(dai_data->port); + + return 0; +} + +static struct platform_driver q6afe_dai_driver = { + .probe = q6afe_dai_dev_probe, + .remove = q6afe_dai_dev_remove, + .driver = { + .name = "q6afe_dai", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(q6afe_dai_driver); From patchwork Tue Dec 5 22:18:10 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 120769 Delivered-To: patch@linaro.org Received: by 10.140.22.227 with SMTP id 90csp6314288qgn; Tue, 5 Dec 2017 14:24:13 -0800 (PST) X-Google-Smtp-Source: AGs4zMaJ0J9LBfgvGLy5Z9xNV9cShIjhG9fIhuObTcJJrvD8lBOH2/rb9Rb/BJr0WxMPliUOc8W9 X-Received: by 10.101.67.140 with SMTP id m12mr18547442pgp.51.1512512653748; Tue, 05 Dec 2017 14:24:13 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1512512653; cv=none; d=google.com; s=arc-20160816; b=TSNttNnB8IcUSIRaUXYOQrg7qiFYIJQ62K3uQw6zAl/UpP4RU6AtrPKU866ssRUd4y CzUccecnhRV8dOzoOiPIAf8UlPnZxCbSRiDdQgr9SlZfrqHhwA+pAJkqxMX0iPdA9Gzo RkXAjHcNyF4gfqUa5V9+rkmx/eQLWcu/9oZ5QRLzu3BO6jpTEVVqdmogFkoZ6JAacPDF aZpfnHkDYO7xDhxxpvTCwj+WjGAuSwTip1X2WsbrGgir5Jxi9jPnPFxYWgXSo0yG8tXl ZE6fKQc98ZmzS+DRDk4JL4BGTSqMdIw+rM7Z55hb2/MUe4++ZRjDksnhn2ztWrLpqV4A lT2A== 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=kP6W0p110awRV75hctOzMMq1qzFnApTc19eYy1kDQ+4=; b=nVRNkl7eCTAy2x/mRV0JSJGowmJOlxTdD6zo/2o6xf98/LuQFBd7TT4HIgrO0XfqP7 bGpAYkM8R8/c/XWBmOT5zH0II1Kh4YRNDPrvCL5ZG09imlgnSldxEvbCezzt0G7p/TXI rRSs7wh0JJsHIWw/NKU+qwUhwDpIWIm1etEkBvsFp2yeibfh52W7K7Oxzr1FXR5X201n IUghFZf6f/6/od77mjA6kgCiG+UcdCJWt4ff5FVygGKHKbbyLRAIIiN9F2FtcgSb72Bw xcg2TJK1p9Za0P1w1vc4YcIwe7N+u62LxanlxPEgJJQq70fQtr/Ca+XbN0/m37ONtlRf WJxA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=d7SVvufk; 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 m8si797091pfi.343.2017.12.05.14.24.13; Tue, 05 Dec 2017 14:24:13 -0800 (PST) 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=d7SVvufk; 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 S1752833AbdLEWWy (ORCPT + 10 others); Tue, 5 Dec 2017 17:22:54 -0500 Received: from mail-wm0-f65.google.com ([74.125.82.65]:39631 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752588AbdLEWUe (ORCPT ); Tue, 5 Dec 2017 17:20:34 -0500 Received: by mail-wm0-f65.google.com with SMTP id i11so3941670wmf.4 for ; Tue, 05 Dec 2017 14:20:33 -0800 (PST) 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=CIxce/4lZ4m40iDYENrTsK72n8ByRc9vBTJqwEy+D6c=; b=d7SVvufkOeru+YcOPF3OBxcsOREvk6A973Tl1aKsRjOeazIWU6Qdpj5paiMtqztfuc w8LPy92J7Lw6nqKszrH7rD+oWCHXy8iRedJyWWcSlJ9xviL0N4w5WWHfEyXTUQHVrBBM 5MqGZm6WcHfxwXEJlEPQLneJd3dqD3b/BZva8= 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=CIxce/4lZ4m40iDYENrTsK72n8ByRc9vBTJqwEy+D6c=; b=QJqEMo6+p3mRWYeUl+t1uabhCk0VyZrjQaVIAvD6wg9J2XRLT42CPbClivUc36sFwP xsfxNl7NH4kF/sKAqm6QUCurf7b1PWV6FF7H3NzUC4AsZyRJVd+NRmmx68I72x82V6MX WRcmlt4wS0yuCw4uxVxq383cseCziETCqgy+ftcKHf0Y27/9PIn/MJyDBpI+taOu/Ali ZGK0Hbv7VAWvaePtTQdHFwwHE5bRM2kItcpqJKLp/ijMmx5F2bQdo0mxWLGEsCytiiMf JhD/Ox9o0hfHPVTyxoUoqDYHjHExu41FXQQ6hWYEvJAmlt9oIJAZmV53HSSQIJxpC9Xg A32g== X-Gm-Message-State: AKGB3mKn7lVmNzEfDGpwKD6DK2b15iCdwdt7hXWNqH/ky0KgNChHOJpp 5lswEbLBmEaxvCKzVvW2Bzs1VQ== X-Received: by 10.28.66.11 with SMTP id p11mr7328444wma.114.1512512433231; Tue, 05 Dec 2017 14:20:33 -0800 (PST) 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 t138sm1633154wme.16.2017.12.05.14.20.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 05 Dec 2017 14:20:32 -0800 (PST) From: srinivas.kandagatla@linaro.org To: broonie@kernel.org, bgoswami@codeaurora.org Cc: alsa-devel@alsa-project.org, tiwai@suse.com, plai@codeaurora.org, kwestfie@codeaurora.org, linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org, lkasam@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v2 13/15] dt-bindings: sound: qcom: Add devicetree bindings for apq8096 Date: Tue, 5 Dec 2017 22:18:10 +0000 Message-Id: <20171205221812.25641-14-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.15.0 In-Reply-To: <20171205221812.25641-1-srinivas.kandagatla@linaro.org> References: <20171205221812.25641-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 From: Srinivas Kandagatla Add devicetree bindings documentation file for Qualcomm apq8096 sound card. Signed-off-by: Srinivas Kandagatla --- .../devicetree/bindings/sound/qcom,apq8096.txt | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,apq8096.txt -- 2.15.0 -- 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/Documentation/devicetree/bindings/sound/qcom,apq8096.txt b/Documentation/devicetree/bindings/sound/qcom,apq8096.txt new file mode 100644 index 000000000000..27b511dab533 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,apq8096.txt @@ -0,0 +1,22 @@ +* Qualcomm Technologies APQ8096 ASoC sound card driver + +This binding describes the APQ8096 sound card, which uses qdsp for audio. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,apq8096-sndcard" + +- qcom,audio-routing: + Usage: Optional + Value type: + Definition: A list of the connections between audio components. + Each entry is a pair of strings, the first being the + connection's sink, the second being the connection's + source. Valid names could be power supplies, MicBias + of codec and the jacks on the board: +Example: + sound { + compatible = "qcom,snd-apq8096"; + qcom,model = "DB820c"; + };