All of lore.kernel.org
 help / color / mirror / Atom feed
From: Liam Girdwood <liam.r.girdwood@linux.intel.com>
To: alsa-devel@alsa-project.org
Cc: Liam Girdwood <liam.r.girdwood@linux.intel.com>,
	Mark Brown <broonie@kernel.org>
Subject: [PATCH v2 02/12] ASoC: SOF: Add Sound Open Firmware KControl support
Date: Fri, 31 Aug 2018 16:19:00 +0100	[thread overview]
Message-ID: <20180831151910.16122-3-liam.r.girdwood@linux.intel.com> (raw)
In-Reply-To: <20180831151910.16122-1-liam.r.girdwood@linux.intel.com>

SOF exposes regular ALSA Kcontrols that are defined by topology. This
patch converts the Kcontrol IO to DSP IPC.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
---
 sound/soc/sof/control.c | 270 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 270 insertions(+)
 create mode 100644 sound/soc/sof/control.c

diff --git a/sound/soc/sof/control.c b/sound/soc/sof/control.c
new file mode 100644
index 000000000000..03c1a980f141
--- /dev/null
+++ b/sound/soc/sof/control.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+//
+// This file is provided under a dual BSD/GPLv2 license.  When using or
+// redistributing this file, you may do so under either license.
+//
+// Copyright(c) 2018 Intel Corporation. All rights reserved.
+//
+// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+//
+
+/* Mixer Controls */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc-topology.h>
+#include <sound/soc.h>
+#include <sound/control.h>
+#include <uapi/sound/sof-ipc.h>
+#include "sof-priv.h"
+
+static inline u32 mixer_to_ipc(unsigned int value, u32 *volume_map, int size)
+{
+	if (value >= size)
+		return volume_map[size - 1];
+	else
+		return volume_map[value];
+}
+
+static inline u32 ipc_to_mixer(u32 value, u32 *volume_map, int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		if (volume_map[i] >= value)
+			return i;
+	}
+
+	return i - 1;
+}
+
+int snd_sof_volume_get(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *sm =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = sm->dobj.private;
+	struct snd_sof_dev *sdev = scontrol->sdev;
+	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
+	unsigned int i, channels = scontrol->num_channels;
+	int err, ret;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: volume get failed to resume %d\n",
+			ret);
+		return ret;
+	}
+
+	/* get all the mixer data from DSP */
+	snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE,
+				  SOF_CTRL_TYPE_VALUE_CHAN_GET,
+				  SOF_CTRL_CMD_VOLUME);
+
+	/* read back each channel */
+	for (i = 0; i < channels; i++)
+		ucontrol->value.integer.value[i] =
+			ipc_to_mixer(cdata->chanv[i].value,
+				     scontrol->volume_table, sm->max + 1);
+
+	pm_runtime_mark_last_busy(sdev->dev);
+	err = pm_runtime_put_autosuspend(sdev->dev);
+	if (err < 0)
+		dev_err(sdev->dev, "error: volume get failed to idle %d\n",
+			err);
+	return 0;
+}
+
+int snd_sof_volume_put(struct snd_kcontrol *kcontrol,
+		       struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_mixer_control *sm =
+		(struct soc_mixer_control *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = sm->dobj.private;
+	struct snd_sof_dev *sdev = scontrol->sdev;
+	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
+	unsigned int i, channels = scontrol->num_channels;
+	int ret, err;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: volume put failed to resume %d\n",
+			ret);
+		return ret;
+	}
+
+	/* update each channel */
+	for (i = 0; i < channels; i++) {
+		cdata->chanv[i].value =
+			mixer_to_ipc(ucontrol->value.integer.value[i],
+				     scontrol->volume_table, sm->max + 1);
+		cdata->chanv[i].channel = i;
+	}
+
+	/* notify DSP of mixer updates */
+	snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE,
+				  SOF_CTRL_TYPE_VALUE_CHAN_GET,
+				  SOF_CTRL_CMD_VOLUME);
+
+	pm_runtime_mark_last_busy(sdev->dev);
+	err = pm_runtime_put_autosuspend(sdev->dev);
+	if (err < 0)
+		dev_err(sdev->dev, "error: volume put failed to idle %d\n",
+			err);
+	return 0;
+}
+
+int snd_sof_enum_get(struct snd_kcontrol *kcontrol,
+		     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *se =
+		(struct soc_enum *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = se->dobj.private;
+	struct snd_sof_dev *sdev = scontrol->sdev;
+	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
+	unsigned int i, channels = scontrol->num_channels;
+	int err, ret;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: enum get failed to resume %d\n",
+			ret);
+		return ret;
+	}
+
+	/* get all the mixer data from DSP */
+	snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_VALUE,
+				  SOF_CTRL_TYPE_VALUE_CHAN_GET,
+				  SOF_CTRL_CMD_ENUM);
+
+	/* read back each channel */
+	for (i = 0; i < channels; i++)
+		ucontrol->value.integer.value[i] = cdata->chanv[i].value;
+
+	pm_runtime_mark_last_busy(sdev->dev);
+	err = pm_runtime_put_autosuspend(sdev->dev);
+	if (err < 0)
+		dev_err(sdev->dev, "error: enum get failed to idle %d\n",
+			ret);
+	return 0;
+}
+
+int snd_sof_enum_put(struct snd_kcontrol *kcontrol,
+		     struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_enum *se =
+		(struct soc_enum *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = se->dobj.private;
+	struct snd_sof_dev *sdev = scontrol->sdev;
+	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
+	unsigned int i, channels = scontrol->num_channels;
+	int ret, err;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: enum put failed to resume %d\n",
+			ret);
+		return ret;
+	}
+
+	/* update each channel */
+	for (i = 0; i < channels; i++)
+		cdata->chanv[i].value = ucontrol->value.integer.value[i];
+
+	/* notify DSP of mixer updates */
+	snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_VALUE,
+				  SOF_CTRL_TYPE_VALUE_CHAN_SET,
+				  SOF_CTRL_CMD_ENUM);
+
+	pm_runtime_mark_last_busy(sdev->dev);
+	err = pm_runtime_put_autosuspend(sdev->dev);
+	if (err < 0)
+		dev_err(sdev->dev, "error: enum put failed to idle %d\n",
+			err);
+	return 0;
+}
+
+int snd_sof_bytes_get(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes_ext *be =
+		(struct soc_bytes_ext *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = be->dobj.private;
+	struct snd_sof_dev *sdev = scontrol->sdev;
+	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
+	struct sof_abi_hdr *data = cdata->data;
+	size_t size;
+	int ret, err;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: bytes get failed to resume %d\n",
+			ret);
+		return ret;
+	}
+
+	/* get all the mixer data from DSP */
+	snd_sof_ipc_get_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_GET_DATA,
+				  SOF_CTRL_TYPE_DATA_GET, scontrol->cmd);
+	size = data->size + sizeof(*data);
+	if (size > be->max) {
+		dev_err(sdev->dev, "error: DSP sent %zu bytes max is %d\n",
+			size, be->max);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* copy back to kcontrol */
+	memcpy(ucontrol->value.bytes.data, data, size);
+
+out:
+	pm_runtime_mark_last_busy(sdev->dev);
+	err = pm_runtime_put_autosuspend(sdev->dev);
+	if (err < 0)
+		dev_err(sdev->dev, "error: bytes get failed to idle %d\n",
+			err);
+	return ret;
+}
+
+int snd_sof_bytes_put(struct snd_kcontrol *kcontrol,
+		      struct snd_ctl_elem_value *ucontrol)
+{
+	struct soc_bytes_ext *be =
+		(struct soc_bytes_ext *)kcontrol->private_value;
+	struct snd_sof_control *scontrol = be->dobj.private;
+	struct snd_sof_dev *sdev = scontrol->sdev;
+	struct sof_ipc_ctrl_data *cdata = scontrol->control_data;
+	struct sof_abi_hdr *data = cdata->data;
+	int ret, err;
+
+	ret = pm_runtime_get_sync(sdev->dev);
+	if (ret < 0) {
+		dev_err(sdev->dev, "error: bytes put failed to resume %d\n",
+			ret);
+		return ret;
+	}
+
+	if (data->size > be->max) {
+		dev_err(sdev->dev, "error: size too big %d bytes max is %d\n",
+			data->size, be->max);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* copy from kcontrol */
+	memcpy(data, ucontrol->value.bytes.data, data->size);
+
+	/* notify DSP of mixer updates */
+	snd_sof_ipc_set_comp_data(sdev->ipc, scontrol, SOF_IPC_COMP_SET_DATA,
+				  SOF_CTRL_TYPE_DATA_SET, scontrol->cmd);
+
+out:
+	pm_runtime_mark_last_busy(sdev->dev);
+	err = pm_runtime_put_autosuspend(sdev->dev);
+	if (err < 0)
+		dev_err(sdev->dev, "error: volume get failed to idle %d\n",
+			err);
+	return ret;
+}
-- 
2.17.1

  parent reply	other threads:[~2018-08-31 15:19 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-31 15:18 [PATCH v2 00/12] Sound Open Firmware Core Liam Girdwood
2018-08-31 15:18 ` [PATCH v2 01/12] ASoC: SOF: Add Sound Open Firmware driver core Liam Girdwood
2018-09-03 15:07   ` Mark Brown
2018-08-31 15:19 ` Liam Girdwood [this message]
2018-08-31 15:19 ` [PATCH v2 03/12] ASoC: SOF: Add driver debug support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 04/12] ASoC: SOF: Add support for IPC IO between DSP and Host Liam Girdwood
2018-09-03 15:53   ` Mark Brown
2018-09-04 13:15     ` Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 05/12] ASoC: SOF: Add PCM operations support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 06/12] ASoC: SOF: Add support for loading topologies Liam Girdwood
2018-09-03 16:19   ` Mark Brown
2018-08-31 15:19 ` [PATCH v2 07/12] ASoC: SOF: Add DSP firmware trace event support Liam Girdwood
2018-09-03 16:25   ` Mark Brown
2018-09-04 13:21     ` Liam Girdwood
2018-09-04 15:03       ` Mark Brown
2018-09-04 15:28         ` Liam Girdwood
2018-09-04 15:46           ` Mark Brown
2018-09-20 16:02             ` Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 08/12] ASoC: SOF: Add DSP HW abstraction operations Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 09/12] ASoC: SOF: Add firmware loader support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 10/12] ASoC: SOF: Add PM support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 11/12] ASoC: SOF: Add userspace ABI support Liam Girdwood
2018-08-31 15:19 ` [PATCH v2 12/12] ASoC: SOF: Add Build support for SOF core Liam Girdwood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180831151910.16122-3-liam.r.girdwood@linux.intel.com \
    --to=liam.r.girdwood@linux.intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.