mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-17 02:36:21 +00:00
ASoC: intel/sdw-utils: move soundwire machine driver soc ops
Move Intel SoundWire generic machine driver soc ops to common place so that it can be used by other platform machine driver. Link: https://github.com/thesofproject/linux/pull/5068 Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com> Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com> Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com> Link: https://patch.msgid.link/20240801091446.10457-8-Vijendar.Mukunda@amd.com Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
parent
b1f7cbf0d5
commit
d39388e655
23
include/sound/soc_sdw_utils.h
Normal file
23
include/sound/soc_sdw_utils.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* This file incorporates work covered by the following copyright notice:
|
||||
* Copyright (c) 2020 Intel Corporation
|
||||
* Copyright(c) 2024 Advanced Micro Devices, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SOC_SDW_UTILS_H
|
||||
#define SOC_SDW_UTILS_H
|
||||
|
||||
#include <sound/soc.h>
|
||||
|
||||
int asoc_sdw_startup(struct snd_pcm_substream *substream);
|
||||
int asoc_sdw_prepare(struct snd_pcm_substream *substream);
|
||||
int asoc_sdw_prepare(struct snd_pcm_substream *substream);
|
||||
int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd);
|
||||
int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
int asoc_sdw_hw_free(struct snd_pcm_substream *substream);
|
||||
void asoc_sdw_shutdown(struct snd_pcm_substream *substream);
|
||||
|
||||
#endif
|
@ -126,6 +126,8 @@ source "sound/soc/xtensa/Kconfig"
|
||||
# Supported codecs
|
||||
source "sound/soc/codecs/Kconfig"
|
||||
|
||||
source "sound/soc/sdw_utils/Kconfig"
|
||||
|
||||
# generic frame-work
|
||||
source "sound/soc/generic/Kconfig"
|
||||
|
||||
|
@ -75,3 +75,4 @@ obj-$(CONFIG_SND_SOC) += uniphier/
|
||||
obj-$(CONFIG_SND_SOC) += ux500/
|
||||
obj-$(CONFIG_SND_SOC) += xilinx/
|
||||
obj-$(CONFIG_SND_SOC) += xtensa/
|
||||
obj-$(CONFIG_SND_SOC) += sdw_utils/
|
||||
|
@ -656,6 +656,7 @@ config SND_SOC_INTEL_SOUNDWIRE_SOF_MACH
|
||||
depends on MFD_INTEL_LPSS || COMPILE_TEST
|
||||
depends on SND_SOC_INTEL_USER_FRIENDLY_LONG_NAMES || COMPILE_TEST
|
||||
depends on SOUNDWIRE
|
||||
select SND_SOC_SDW_UTILS
|
||||
select SND_SOC_MAX98363
|
||||
select SND_SOC_MAX98373_I2C
|
||||
select SND_SOC_MAX98373_SDW
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-acpi.h>
|
||||
#include "sof_sdw_common.h"
|
||||
#include "../../codecs/rt711.h"
|
||||
@ -593,135 +592,6 @@ static const struct snd_kcontrol_new rt700_controls[] = {
|
||||
SOC_DAPM_PIN_SWITCH("Speaker"),
|
||||
};
|
||||
|
||||
/* these wrappers are only needed to avoid typecast compilation errors */
|
||||
int asoc_sdw_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return sdw_startup_stream(substream);
|
||||
}
|
||||
|
||||
int asoc_sdw_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
struct snd_soc_dai *dai;
|
||||
|
||||
/* Find stream from first CPU DAI */
|
||||
dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
|
||||
if (IS_ERR(sdw_stream)) {
|
||||
dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
|
||||
return PTR_ERR(sdw_stream);
|
||||
}
|
||||
|
||||
return sdw_prepare_stream(sdw_stream);
|
||||
}
|
||||
|
||||
int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
struct snd_soc_dai *dai;
|
||||
int ret;
|
||||
|
||||
/* Find stream from first CPU DAI */
|
||||
dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
|
||||
if (IS_ERR(sdw_stream)) {
|
||||
dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
|
||||
return PTR_ERR(sdw_stream);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
ret = sdw_enable_stream(sdw_stream);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
ret = sdw_disable_stream(sdw_stream);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int ch = params_channels(params);
|
||||
unsigned int ch_mask;
|
||||
int num_codecs;
|
||||
int step;
|
||||
int i;
|
||||
|
||||
if (!rtd->dai_link->ch_maps)
|
||||
return 0;
|
||||
|
||||
/* Identical data will be sent to all codecs in playback */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ch_mask = GENMASK(ch - 1, 0);
|
||||
step = 0;
|
||||
} else {
|
||||
num_codecs = rtd->dai_link->num_codecs;
|
||||
|
||||
if (ch < num_codecs || ch % num_codecs != 0) {
|
||||
dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
|
||||
ch, num_codecs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch_mask = GENMASK(ch / num_codecs - 1, 0);
|
||||
step = hweight_long(ch_mask);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The captured data will be combined from each cpu DAI if the dai
|
||||
* link has more than one codec DAIs. Set codec channel mask and
|
||||
* ASoC will set the corresponding channel numbers for each cpu dai.
|
||||
*/
|
||||
for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
|
||||
ch_maps->ch_mask = ch_mask << (i * step);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
struct snd_soc_dai *dai;
|
||||
|
||||
/* Find stream from first CPU DAI */
|
||||
dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
|
||||
if (IS_ERR(sdw_stream)) {
|
||||
dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
|
||||
return PTR_ERR(sdw_stream);
|
||||
}
|
||||
|
||||
return sdw_deprepare_stream(sdw_stream);
|
||||
}
|
||||
|
||||
void asoc_sdw_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
sdw_shutdown_stream(substream);
|
||||
}
|
||||
|
||||
static const struct snd_soc_ops sdw_ops = {
|
||||
.startup = asoc_sdw_startup,
|
||||
.prepare = asoc_sdw_prepare,
|
||||
@ -2232,3 +2102,4 @@ MODULE_AUTHOR("Rander Wang <rander.wang@linux.intel.com>");
|
||||
MODULE_AUTHOR("Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
|
||||
MODULE_IMPORT_NS(SND_SOC_SDW_UTILS);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/bits.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc_sdw_utils.h>
|
||||
#include "sof_hdmi_common.h"
|
||||
|
||||
#define SOC_SDW_MAX_NO_PROPS 2
|
||||
@ -134,14 +135,6 @@ struct mc_private {
|
||||
|
||||
extern unsigned long sof_sdw_quirk;
|
||||
|
||||
int asoc_sdw_startup(struct snd_pcm_substream *substream);
|
||||
int asoc_sdw_prepare(struct snd_pcm_substream *substream);
|
||||
int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd);
|
||||
int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params);
|
||||
int asoc_sdw_hw_free(struct snd_pcm_substream *substream);
|
||||
void asoc_sdw_shutdown(struct snd_pcm_substream *substream);
|
||||
|
||||
/* generic HDMI support */
|
||||
int sof_sdw_hdmi_init(struct snd_soc_pcm_runtime *rtd);
|
||||
|
||||
|
6
sound/soc/sdw_utils/Kconfig
Normal file
6
sound/soc/sdw_utils/Kconfig
Normal file
@ -0,0 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config SND_SOC_SDW_UTILS
|
||||
tristate
|
||||
help
|
||||
This option enables to use SoundWire common helper functions and
|
||||
SoundWire codec helper functions in machine driver.
|
3
sound/soc/sdw_utils/Makefile
Normal file
3
sound/soc/sdw_utils/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
snd-soc-sdw-utils-y := soc_sdw_utils.o
|
||||
obj-$(CONFIG_SND_SOC_SDW_UTILS) += snd-soc-sdw-utils.o
|
150
sound/soc/sdw_utils/soc_sdw_utils.c
Normal file
150
sound/soc/sdw_utils/soc_sdw_utils.c
Normal file
@ -0,0 +1,150 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
// This file incorporates work covered by the following copyright notice:
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
// Copyright(c) 2024 Advanced Micro Devices, Inc.
|
||||
/*
|
||||
* soc-sdw-utils.c - common SoundWire machine driver helper functions
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
#include <linux/soundwire/sdw_type.h>
|
||||
#include <sound/soc_sdw_utils.h>
|
||||
|
||||
/* these wrappers are only needed to avoid typecast compilation errors */
|
||||
int asoc_sdw_startup(struct snd_pcm_substream *substream)
|
||||
{
|
||||
return sdw_startup_stream(substream);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_startup, SND_SOC_SDW_UTILS);
|
||||
|
||||
int asoc_sdw_prepare(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
struct snd_soc_dai *dai;
|
||||
|
||||
/* Find stream from first CPU DAI */
|
||||
dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
|
||||
if (IS_ERR(sdw_stream)) {
|
||||
dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
|
||||
return PTR_ERR(sdw_stream);
|
||||
}
|
||||
|
||||
return sdw_prepare_stream(sdw_stream);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_prepare, SND_SOC_SDW_UTILS);
|
||||
|
||||
int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
struct snd_soc_dai *dai;
|
||||
int ret;
|
||||
|
||||
/* Find stream from first CPU DAI */
|
||||
dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
|
||||
if (IS_ERR(sdw_stream)) {
|
||||
dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
|
||||
return PTR_ERR(sdw_stream);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
ret = sdw_enable_stream(sdw_stream);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
ret = sdw_disable_stream(sdw_stream);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
dev_err(rtd->dev, "%s trigger %d failed: %d\n", __func__, cmd, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_trigger, SND_SOC_SDW_UTILS);
|
||||
|
||||
int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct snd_soc_dai_link_ch_map *ch_maps;
|
||||
int ch = params_channels(params);
|
||||
unsigned int ch_mask;
|
||||
int num_codecs;
|
||||
int step;
|
||||
int i;
|
||||
|
||||
if (!rtd->dai_link->ch_maps)
|
||||
return 0;
|
||||
|
||||
/* Identical data will be sent to all codecs in playback */
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
ch_mask = GENMASK(ch - 1, 0);
|
||||
step = 0;
|
||||
} else {
|
||||
num_codecs = rtd->dai_link->num_codecs;
|
||||
|
||||
if (ch < num_codecs || ch % num_codecs != 0) {
|
||||
dev_err(rtd->dev, "Channels number %d is invalid when codec number = %d\n",
|
||||
ch, num_codecs);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ch_mask = GENMASK(ch / num_codecs - 1, 0);
|
||||
step = hweight_long(ch_mask);
|
||||
}
|
||||
|
||||
/*
|
||||
* The captured data will be combined from each cpu DAI if the dai
|
||||
* link has more than one codec DAIs. Set codec channel mask and
|
||||
* ASoC will set the corresponding channel numbers for each cpu dai.
|
||||
*/
|
||||
for_each_link_ch_maps(rtd->dai_link, i, ch_maps)
|
||||
ch_maps->ch_mask = ch_mask << (i * step);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_hw_params, SND_SOC_SDW_UTILS);
|
||||
|
||||
int asoc_sdw_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
|
||||
struct sdw_stream_runtime *sdw_stream;
|
||||
struct snd_soc_dai *dai;
|
||||
|
||||
/* Find stream from first CPU DAI */
|
||||
dai = snd_soc_rtd_to_cpu(rtd, 0);
|
||||
|
||||
sdw_stream = snd_soc_dai_get_stream(dai, substream->stream);
|
||||
if (IS_ERR(sdw_stream)) {
|
||||
dev_err(rtd->dev, "no stream found for DAI %s\n", dai->name);
|
||||
return PTR_ERR(sdw_stream);
|
||||
}
|
||||
|
||||
return sdw_deprepare_stream(sdw_stream);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_hw_free, SND_SOC_SDW_UTILS);
|
||||
|
||||
void asoc_sdw_shutdown(struct snd_pcm_substream *substream)
|
||||
{
|
||||
sdw_shutdown_stream(substream);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(asoc_sdw_shutdown, SND_SOC_SDW_UTILS);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SoundWire ASoC helpers");
|
Loading…
x
Reference in New Issue
Block a user