forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: 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
1 parent
b1f7cbf
commit d39388e
Showing
9 changed files
with
188 additions
and
138 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 <[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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); |