Skip to content

Commit

Permalink
ASoC: intel/sdw-utils: move soundwire machine driver soc ops
Browse files Browse the repository at this point in the history
Move Intel SoundWire generic machine driver soc ops to common place
so that it can be used by other platform machine driver.

Link: thesofproject#5068
Signed-off-by: Vijendar Mukunda <[email protected]>
Reviewed-by: Bard Liao <[email protected]>
Reviewed-by: Pierre-Louis Bossart <[email protected]>
Link: https://patch.msgid.link/[email protected]
Signed-off-by: Mark Brown <[email protected]>
  • Loading branch information
vijendarmukunda authored and broonie committed Aug 1, 2024
1 parent b1f7cbf commit d39388e
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 138 deletions.
23 changes: 23 additions & 0 deletions include/sound/soc_sdw_utils.h
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions sound/soc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
1 change: 1 addition & 0 deletions sound/soc/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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/
1 change: 1 addition & 0 deletions sound/soc/intel/boards/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
131 changes: 1 addition & 130 deletions sound/soc/intel/boards/sof_sdw.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -2232,3 +2102,4 @@ MODULE_AUTHOR("Rander Wang <[email protected]>");
MODULE_AUTHOR("Pierre-Louis Bossart <[email protected]>");
MODULE_LICENSE("GPL v2");
MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON);
MODULE_IMPORT_NS(SND_SOC_SDW_UTILS);
9 changes: 1 addition & 8 deletions sound/soc/intel/boards/sof_sdw_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);

Expand Down
6 changes: 6 additions & 0 deletions sound/soc/sdw_utils/Kconfig
Original file line number Diff line number Diff line change
@@ -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 changes: 3 additions & 0 deletions sound/soc/sdw_utils/Makefile
Original file line number Diff line number Diff line change
@@ -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 changes: 150 additions & 0 deletions sound/soc/sdw_utils/soc_sdw_utils.c
Original file line number Diff line number Diff line change
@@ -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");

0 comments on commit d39388e

Please sign in to comment.