From patchwork Tue Feb 13 16:58:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 128283 Delivered-To: patch@linaro.org Received: by 10.46.124.24 with SMTP id x24csp4463052ljc; Tue, 13 Feb 2018 09:06:38 -0800 (PST) X-Google-Smtp-Source: AH8x226vfza3Z+LL9ulfy3G3jy5Fh0+3WrC94znVRszGI2f9SuF73w4jd+/lkotCBbg6Wykr04Di X-Received: by 10.101.69.202 with SMTP id m10mr1536874pgr.198.1518541598027; Tue, 13 Feb 2018 09:06:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518541598; cv=none; d=google.com; s=arc-20160816; b=uuT5etGn//7ggZlql8ZsuaqfcYoZaCaMoRjEYPw8Pn4zuVkesz2zY+YjL/6F6To4tP k7gKc/uBFGoTlu5k2fxLrsswk3OW1E1Gg3xLylcISWhHR08zcCtC4ZXBaDT6xtRR5g2E yKda6V/MCllBKvFerK304j9yoq23EtX+pcwcHgRN0ZZcDx9GEgiupmrfGLOevCHL0Ems MkvFqK4pD/LkKUtOtuQHzsp1dIT++5oRtsMnN5t7WOM302bO6tTmvfi3D7y6G8B1an8K 8PdynDMkXGDPsyF0OKQm0sHD7XuEQNyev/3E/x3NowaTQ7+9ziqsysRAtabTIdyWr+bi 3VQQ== 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=NzXx/7xx90cj4vNHdnWI3nyfy1k7UcSOr4DBdxOe+ko=; b=KCksY4NC6fvMXCfySAaH4N/r0sQM6zlqyb14kZsMqaRfUu8UJFDdxz1uOa2zcmupVc Uo93e0zk4j0gudI/qD9/lhC35jmHyYikBQhU7z9z3RklgbO3p4yIjAxNPDgelVTRz+HS ku+lbiSM4mdv84hWCW5kS8kDapHGwqXvkFFlU5iOkebm+vqC1kWMgZ8hrxlp+nlzy7jX P9lZCES0iOiQ/jQjsbxljUcruTAa3dhqifNgqRLZ8dHURqXnZc3qhFuU362RNsOJ3Qkn rK3rfryCvbcAI/RS1nawCoS8R1gsjXiQlmHqlUS6A5rbj0qRSIxcyEUItx1mYRHEgnHM htGQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=e4irG1zK; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (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 h15-v6si4159652pli.212.2018.02.13.09.06.37; Tue, 13 Feb 2018 09:06:38 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=e4irG1zK; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965563AbeBMRFg (ORCPT + 28 others); Tue, 13 Feb 2018 12:05:36 -0500 Received: from mail-wr0-f195.google.com ([209.85.128.195]:36713 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S965167AbeBMRBf (ORCPT ); Tue, 13 Feb 2018 12:01:35 -0500 Received: by mail-wr0-f195.google.com with SMTP id y3so19304691wrh.3 for ; Tue, 13 Feb 2018 09:01:34 -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=NzXx/7xx90cj4vNHdnWI3nyfy1k7UcSOr4DBdxOe+ko=; b=e4irG1zKtc36AuFORVQr+ldB6ny6cwxhQtzPm4Dr35RW2FEo40viZtQNLY10hkQULs JRKCIiai+gcxOTWRjjlDF9PuEk+M0Zqi8p1zLJCAmOqrtkNrAfHPyYUhRQpcLpAsHdt5 rxk5YC7b6o5tpuAGMxenH0JiZfRMsCf0Nq8AQ= 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=NzXx/7xx90cj4vNHdnWI3nyfy1k7UcSOr4DBdxOe+ko=; b=YBXg8/F+QCyJ7rnLHSlbucIf8O7dsVB1glF0xtKKt9mDMk2z/stI8N48PjqUCLgALs VFTZcDtEFoagPK1iVJNTRBZ+/QJ2Fn0Jy5rDp9ptARTAMUu33i1CAIBi3BJOFMQdbJe2 l3d2XNGjz8eot7+5q757MTX+YPe4X8g3QYK+oMWWndXoFnk30w0O9o/K3CHfKhjEQYHI E25qGFVWe06YbIOAuTv4LHUIx2Zt9GW4cuEbSL2yb2lwDLiZkKPDuVZde5jf+P4uuXVO U7c9qT9yYSOAlzpo6zq4QvdQDmrOqyYjXdCyiZvfnuS7UnP4ryaI74bGWarjyn22+xmc gUNA== X-Gm-Message-State: APf1xPC/OFO1H/5k9kzwhvwxLKLvOmBmx7cUPnCHcFWcZ5aTCgcKzPzO PfyJAtmVWHNGb52gAEN2C1Mw7Q== X-Received: by 10.223.160.82 with SMTP id l18mr1820874wrl.76.1518541293363; Tue, 13 Feb 2018 09:01: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 y145sm7432723wmd.43.2018.02.13.09.01.32 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 13 Feb 2018 09:01:32 -0800 (PST) From: srinivas.kandagatla@linaro.org To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org Cc: david.brown@linaro.org, robh+dt@kernel.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, bgoswami@codeaurora.org, perex@perex.cz, tiwai@suse.com, linux-soc@vger.kernel.org, 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 v3 14/25] ASoC: qcom: qdsp6: Add support to q6afe dai driver Date: Tue, 13 Feb 2018 16:58:26 +0000 Message-Id: <20180213165837.1620-15-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.15.1 In-Reply-To: <20180213165837.1620-1-srinivas.kandagatla@linaro.org> References: <20180213165837.1620-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Srinivas Kandagatla This patch adds support to q6afe backend dais driver. Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/qdsp6/Makefile | 2 +- sound/soc/qcom/qdsp6/q6afe-dai.c | 280 +++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6afe.h | 3 + 3 files changed, 284 insertions(+), 1 deletion(-) create mode 100644 sound/soc/qcom/qdsp6/q6afe-dai.c -- 2.15.1 diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 660afcab98fd..c7833842b878 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,5 +1,5 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o -obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o +obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o q6afe-dai.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o q6routing.o obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.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..f6a618e9db9e --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -0,0 +1,280 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2011-2016, The Linux Foundation + * Copyright (c) 2018, Linaro Limited + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6afe.h" + +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]; +}; + +static int q6hdmi_format_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct q6afe_dai_data *dai_data = kcontrol->private_data; + int value = ucontrol->value.integer.value[0]; + + dai_data->port_config[AFE_PORT_HDMI_RX].hdmi.datatype = value; + + return 0; +} + +static int q6hdmi_format_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + + struct q6afe_dai_data *dai_data = kcontrol->private_data; + + ucontrol->value.integer.value[0] = + dai_data->port_config[AFE_PORT_HDMI_RX].hdmi.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 q6afe_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 q6afe_dai_data *dai_data = q6afe_get_dai_data(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; + } + + /*refer to 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 q6afe_dai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = q6afe_get_dai_data(dai->dev); + + dai_data->is_port_started[dai->id] = false; + + return 0; +} + +static void q6afe_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = q6afe_get_dai_data(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\n"); + + dai_data->is_port_started[dai->id] = false; + +} + +static int q6afe_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = q6afe_get_dai_data(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\n"); + return rc; + } + } + + if (dai->id == AFE_PORT_HDMI_RX) + q6afe_hdmi_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].hdmi); + + 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 const struct snd_soc_dapm_route q6afe_dapm_routes[] = { + {"HDMI Playback", NULL, "HDMI_RX"}, +}; + +static struct snd_soc_dai_ops q6hdmi_ops = { + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, + .startup = q6afe_dai_startup, +}; + +static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = q6afe_get_dai_data(dai->dev); + struct snd_soc_dapm_context *dapm; + struct q6afe_port *port; + + dapm = snd_soc_component_get_dapm(dai->component); + + 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 = q6afe_get_dai_data(dai->dev); + + q6afe_port_put(dai_data->port[dai->id]); + + 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 = AFE_PORT_HDMI_RX, + .name = "HDMI", + .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 i, ret = -EINVAL; + + 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), +}; + +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), + .controls = q6afe_config_controls, + .num_controls = ARRAY_SIZE(q6afe_config_controls), + .dapm_routes = q6afe_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(q6afe_dapm_routes), + .of_xlate_dai_name = q6afe_of_xlate_dai_name, + +}; + +int q6afe_dai_dev_probe(struct device *dev) +{ + int rc = 0; + struct q6afe_dai_data *dai_data; + + dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL); + if (!dai_data) + rc = -ENOMEM; + + q6afe_set_dai_data(dev, dai_data); + + return devm_snd_soc_register_component(dev, &q6afe_dai_component, + q6afe_dais, ARRAY_SIZE(q6afe_dais)); +} +EXPORT_SYMBOL_GPL(q6afe_dai_dev_probe); + +int q6afe_dai_dev_remove(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(q6afe_dai_dev_remove); +MODULE_DESCRIPTION("Q6 Audio Fronend dai driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 43df524f01bb..647ed2d15545 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -26,6 +26,9 @@ struct q6afe_port; void q6afe_set_dai_data(struct device *dev, void *data); void *q6afe_get_dai_data(struct device *dev); +int q6afe_dai_dev_probe(struct device *dev); +int q6afe_dai_dev_remove(struct device *dev); + 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);