2018-07-02 14:22:15 +08:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0
|
|
|
|
*
|
2008-07-23 21:03:07 +08:00
|
|
|
* linux/sound/soc-dai.h -- ALSA SoC Layer
|
|
|
|
*
|
|
|
|
* Copyright: 2005-2008 Wolfson Microelectronics. PLC.
|
|
|
|
*
|
|
|
|
* Digital Audio Interface (DAI) API.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __LINUX_SND_SOC_DAI_H
|
|
|
|
#define __LINUX_SND_SOC_DAI_H
|
|
|
|
|
|
|
|
|
|
|
|
#include <linux/list.h>
|
2016-09-29 14:09:14 +08:00
|
|
|
#include <sound/asoc.h>
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
struct snd_pcm_substream;
|
2012-02-17 11:37:51 +08:00
|
|
|
struct snd_soc_dapm_widget;
|
2012-08-16 19:40:40 +08:00
|
|
|
struct snd_compr_stream;
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* DAI hardware audio formats.
|
|
|
|
*
|
|
|
|
* Describes the physical PCM data formating and clocking. Add new formats
|
|
|
|
* to the end.
|
|
|
|
*/
|
2016-09-29 14:09:14 +08:00
|
|
|
#define SND_SOC_DAIFMT_I2S SND_SOC_DAI_FORMAT_I2S
|
|
|
|
#define SND_SOC_DAIFMT_RIGHT_J SND_SOC_DAI_FORMAT_RIGHT_J
|
|
|
|
#define SND_SOC_DAIFMT_LEFT_J SND_SOC_DAI_FORMAT_LEFT_J
|
|
|
|
#define SND_SOC_DAIFMT_DSP_A SND_SOC_DAI_FORMAT_DSP_A
|
|
|
|
#define SND_SOC_DAIFMT_DSP_B SND_SOC_DAI_FORMAT_DSP_B
|
|
|
|
#define SND_SOC_DAIFMT_AC97 SND_SOC_DAI_FORMAT_AC97
|
|
|
|
#define SND_SOC_DAIFMT_PDM SND_SOC_DAI_FORMAT_PDM
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/* left and right justified also known as MSB and LSB respectively */
|
|
|
|
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
|
|
|
|
#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J
|
|
|
|
|
ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.
This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.
By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.
For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.
This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.
It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.
Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-05-27 10:26:12 +08:00
|
|
|
/* Describes the possible PCM format */
|
|
|
|
/*
|
|
|
|
* use SND_SOC_DAI_FORMAT_xx as eash shift.
|
|
|
|
* see
|
|
|
|
* snd_soc_runtime_get_dai_fmt()
|
|
|
|
*/
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_FORMAT_SHIFT 0
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_FORMAT_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_FORMAT_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_I2S (1 << SND_SOC_DAI_FORMAT_I2S)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_RIGHT_J (1 << SND_SOC_DAI_FORMAT_RIGHT_J)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_LEFT_J (1 << SND_SOC_DAI_FORMAT_LEFT_J)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_DSP_A (1 << SND_SOC_DAI_FORMAT_DSP_A)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_DSP_B (1 << SND_SOC_DAI_FORMAT_DSP_B)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_AC97 (1 << SND_SOC_DAI_FORMAT_AC97)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_PDM (1 << SND_SOC_DAI_FORMAT_PDM)
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/*
|
|
|
|
* DAI Clock gating.
|
|
|
|
*
|
2020-07-19 08:33:07 +08:00
|
|
|
* DAI bit clocks can be gated (disabled) when the DAI is not
|
2008-07-23 21:03:07 +08:00
|
|
|
* sending or receiving PCM data in a frame. This can be used to save power.
|
|
|
|
*/
|
2011-09-27 23:41:01 +08:00
|
|
|
#define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */
|
2013-01-30 13:03:13 +08:00
|
|
|
#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */
|
2008-07-23 21:03:07 +08:00
|
|
|
|
ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.
This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.
By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.
For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.
This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.
It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.
Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-05-27 10:26:12 +08:00
|
|
|
/* Describes the possible PCM format */
|
|
|
|
/*
|
|
|
|
* define GATED -> CONT. GATED will be selected if both are selected.
|
|
|
|
* see
|
|
|
|
* snd_soc_runtime_get_dai_fmt()
|
|
|
|
*/
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT 16
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_GATED (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CONT (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/*
|
2015-10-09 00:37:51 +08:00
|
|
|
* DAI hardware signal polarity.
|
2008-07-23 21:03:07 +08:00
|
|
|
*
|
|
|
|
* Specifies whether the DAI can also support inverted clocks for the specified
|
|
|
|
* format.
|
2015-10-09 00:37:51 +08:00
|
|
|
*
|
|
|
|
* BCLK:
|
|
|
|
* - "normal" polarity means signal is available at rising edge of BCLK
|
|
|
|
* - "inverted" polarity means signal is available at falling edge of BCLK
|
|
|
|
*
|
|
|
|
* FSYNC "normal" polarity depends on the frame format:
|
|
|
|
* - I2S: frame consists of left then right channel data. Left channel starts
|
|
|
|
* with falling FSYNC edge, right channel starts with rising FSYNC edge.
|
|
|
|
* - Left/Right Justified: frame consists of left then right channel data.
|
|
|
|
* Left channel starts with rising FSYNC edge, right channel starts with
|
|
|
|
* falling FSYNC edge.
|
|
|
|
* - DSP A/B: Frame starts with rising FSYNC edge.
|
|
|
|
* - AC97: Frame starts with rising FSYNC edge.
|
|
|
|
*
|
|
|
|
* "Negative" FSYNC polarity is the one opposite of "normal" polarity.
|
2008-07-23 21:03:07 +08:00
|
|
|
*/
|
2013-01-16 12:18:23 +08:00
|
|
|
#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */
|
2011-09-27 23:41:01 +08:00
|
|
|
#define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */
|
|
|
|
#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
|
|
|
|
#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */
|
2008-07-23 21:03:07 +08:00
|
|
|
|
ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.
This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.
By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.
For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.
This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.
It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.
Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-05-27 10:26:12 +08:00
|
|
|
/* Describes the possible PCM format */
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT 32
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_INV_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_NB_NF (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_NB_IF (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_IB_NF (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_IB_IF (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/*
|
2020-11-13 00:30:57 +08:00
|
|
|
* DAI hardware clock providers/consumers
|
2008-07-23 21:03:07 +08:00
|
|
|
*
|
|
|
|
* This is wrt the codec, the inverse is true for the interface
|
2020-11-13 00:30:57 +08:00
|
|
|
* i.e. if the codec is clk and FRM provider then the interface is
|
|
|
|
* clk and frame consumer.
|
2008-07-23 21:03:07 +08:00
|
|
|
*/
|
2020-11-13 00:30:57 +08:00
|
|
|
#define SND_SOC_DAIFMT_CBP_CFP (1 << 12) /* codec clk provider & frame provider */
|
|
|
|
#define SND_SOC_DAIFMT_CBC_CFP (2 << 12) /* codec clk consumer & frame provider */
|
|
|
|
#define SND_SOC_DAIFMT_CBP_CFC (3 << 12) /* codec clk provider & frame consumer */
|
2021-05-12 07:09:08 +08:00
|
|
|
#define SND_SOC_DAIFMT_CBC_CFC (4 << 12) /* codec clk consumer & frame consumer */
|
2020-11-13 00:30:57 +08:00
|
|
|
|
|
|
|
/* previous definitions kept for backwards-compatibility, do not use in new contributions */
|
|
|
|
#define SND_SOC_DAIFMT_CBM_CFM SND_SOC_DAIFMT_CBP_CFP
|
|
|
|
#define SND_SOC_DAIFMT_CBS_CFM SND_SOC_DAIFMT_CBC_CFP
|
|
|
|
#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
|
|
|
|
#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC
|
|
|
|
|
2022-05-19 23:42:23 +08:00
|
|
|
/* when passed to set_fmt directly indicate if the device is provider or consumer */
|
|
|
|
#define SND_SOC_DAIFMT_BP_FP SND_SOC_DAIFMT_CBP_CFP
|
|
|
|
#define SND_SOC_DAIFMT_BC_FP SND_SOC_DAIFMT_CBC_CFP
|
|
|
|
#define SND_SOC_DAIFMT_BP_FC SND_SOC_DAIFMT_CBP_CFC
|
|
|
|
#define SND_SOC_DAIFMT_BC_FC SND_SOC_DAIFMT_CBC_CFC
|
|
|
|
|
ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.
This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.
By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.
For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.
This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.
It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.
Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-05-27 10:26:12 +08:00
|
|
|
/* Describes the possible PCM format */
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT 48
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFP (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFP (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFC (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
|
|
|
|
#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFC (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
|
|
|
|
|
2020-11-13 00:30:57 +08:00
|
|
|
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
|
|
|
|
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
|
|
|
|
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
|
|
|
|
#define SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK 0xf000
|
|
|
|
|
|
|
|
#define SND_SOC_DAIFMT_MASTER_MASK SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Master Clock Directions
|
|
|
|
*/
|
|
|
|
#define SND_SOC_CLOCK_IN 0
|
|
|
|
#define SND_SOC_CLOCK_OUT 1
|
|
|
|
|
2009-08-10 03:08:31 +08:00
|
|
|
#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\
|
|
|
|
SNDRV_PCM_FMTBIT_S16_LE |\
|
|
|
|
SNDRV_PCM_FMTBIT_S16_BE |\
|
|
|
|
SNDRV_PCM_FMTBIT_S20_3LE |\
|
|
|
|
SNDRV_PCM_FMTBIT_S20_3BE |\
|
2017-11-28 06:33:29 +08:00
|
|
|
SNDRV_PCM_FMTBIT_S20_LE |\
|
|
|
|
SNDRV_PCM_FMTBIT_S20_BE |\
|
2009-08-10 03:08:31 +08:00
|
|
|
SNDRV_PCM_FMTBIT_S24_3LE |\
|
|
|
|
SNDRV_PCM_FMTBIT_S24_3BE |\
|
2009-05-14 09:59:14 +08:00
|
|
|
SNDRV_PCM_FMTBIT_S32_LE |\
|
|
|
|
SNDRV_PCM_FMTBIT_S32_BE)
|
2009-05-02 19:24:55 +08:00
|
|
|
|
2010-03-18 04:15:21 +08:00
|
|
|
struct snd_soc_dai_driver;
|
2008-07-23 21:03:07 +08:00
|
|
|
struct snd_soc_dai;
|
|
|
|
struct snd_ac97_bus_ops;
|
|
|
|
|
|
|
|
/* Digital Audio Interface clocking API.*/
|
|
|
|
int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|
|
|
unsigned int freq, int dir);
|
|
|
|
|
|
|
|
int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
|
|
|
|
int div_id, int div);
|
|
|
|
|
|
|
|
int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
|
2009-09-06 01:52:16 +08:00
|
|
|
int pll_id, int source, unsigned int freq_in, unsigned int freq_out);
|
2008-07-23 21:03:07 +08:00
|
|
|
|
2013-09-16 20:01:46 +08:00
|
|
|
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/* Digital Audio interface formatting */
|
ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.
This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.
By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.
For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.
This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.
It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.
Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-05-27 10:26:12 +08:00
|
|
|
int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd);
|
|
|
|
u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority);
|
2008-07-23 21:03:07 +08:00
|
|
|
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
|
|
|
|
|
|
|
|
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
|
2009-06-16 08:44:31 +08:00
|
|
|
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width);
|
2008-07-23 21:03:07 +08:00
|
|
|
|
2009-09-12 01:16:29 +08:00
|
|
|
int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
|
|
|
|
unsigned int tx_num, unsigned int *tx_slot,
|
|
|
|
unsigned int rx_num, unsigned int *rx_slot);
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate);
|
|
|
|
|
|
|
|
/* Digital Audio Interface mute */
|
2013-02-06 23:44:07 +08:00
|
|
|
int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
|
|
|
|
int direction);
|
2008-07-23 21:03:07 +08:00
|
|
|
|
2018-07-23 23:54:03 +08:00
|
|
|
|
|
|
|
int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
|
|
|
|
unsigned int *tx_num, unsigned int *tx_slot,
|
|
|
|
unsigned int *rx_num, unsigned int *rx_slot);
|
|
|
|
|
2014-01-08 18:40:18 +08:00
|
|
|
int snd_soc_dai_is_dummy(struct snd_soc_dai *dai);
|
|
|
|
|
2019-07-22 09:33:04 +08:00
|
|
|
int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
|
|
|
|
struct snd_pcm_substream *substream,
|
|
|
|
struct snd_pcm_hw_params *params);
|
2019-07-22 09:33:19 +08:00
|
|
|
void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
|
ASoC: soc-dai: add mark for snd_soc_dai_hw_params/free()
soc_pcm_hw_params() does rollback when failed (A),
but, it is almost same as soc_pcm_hw_free().
static int soc_pcm_hw_params(xxx)
{
...
if (ret < 0)
goto xxx_err;
...
return ret;
^ component_err:
| ...
| interface_err:
(A) ...
| codec_err:
| ...
v return ret;
}
The difference is
soc_pcm_hw_free() is for all dai/component/substream,
rollback is for succeeded part only.
This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_hw_free() and rollback.
Now, soc_pcm_hw_params/free() are handling
1) snd_soc_link_hw_params/free()
2) snd_soc_pcm_component_hw_params/free()
=> 3) snd_soc_dai_hw_params/free()
This patch is for 3) snd_soc_dai_hw_params/free().
The idea of having bit-flag or counter is not enough for this purpose.
For example if one DAI is used for 2xPlaybacks for some reasons,
and if 1st Playback was succeeded but 2nd Playback was failed,
2nd Playback rollback doesn't need to call shutdown.
But it has succeeded bit-flag or counter via 1st Playback,
thus, 2nd Playback rollback will call unneeded shutdown.
And 1st Playback's necessary shutdown will not be called,
because bit-flag or counter was cleared by wrong 2nd Playback rollback.
To avoid such case, this patch marks substream pointer when hw_params() was
succeeded. If rollback needed, it will check rollback flag and marked
substream pointer.
One note here is that it cares *previous* hw_params() only now,
but we might want to check *whole* marked substream in the future.
This patch is using macro named "push/pop", so that it can be easily
update.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87imbxgqai.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-09-29 12:31:53 +08:00
|
|
|
struct snd_pcm_substream *substream,
|
|
|
|
int rollback);
|
2019-07-22 09:33:32 +08:00
|
|
|
int snd_soc_dai_startup(struct snd_soc_dai *dai,
|
|
|
|
struct snd_pcm_substream *substream);
|
2019-07-22 09:33:39 +08:00
|
|
|
void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
|
ASoC: soc-dai: add mark for snd_soc_dai_startup/shutdown()
soc_pcm_open() does rollback when failed (A),
but, it is almost same as soc_pcm_close().
static int soc_pcm_open(xxx)
{
...
if (ret < 0)
goto xxx_err;
...
return 0;
^ config_err:
| ...
| rtd_startup_err:
(A) ...
| component_err:
| ...
v return ret;
}
The difference is
soc_pcm_close() is for all dai/component/substream,
rollback is for succeeded part only.
This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_close() and rollback.
Now, soc_pcm_open/close() are handling
=> 1) snd_soc_dai_startup/shutdown()
2) snd_soc_link_startup/shutdown()
3) snd_soc_component_module_get/put()
4) snd_soc_component_open/close()
5) pm_runtime_put/get()
This patch is for 1) snd_soc_dai_startup/shutdown().
The idea of having bit-flag or counter is not enough for this purpose.
For example if one DAI is used for 2xPlaybacks for some reasons,
and if 1st Playback was succeeded but 2nd Playback was failed,
2nd Playback rollback doesn't need to call shutdown.
But it has succeeded bit-flag or counter via 1st Playback,
thus, 2nd Playback rollback will call unneeded shutdown.
And 1st Playback's necessary shutdown will not be called,
because bit-flag or counter was cleared by wrong 2nd Playback rollback.
To avoid such case, this patch marks substream pointer when startup() was
succeeded. If rollback needed, it will check rollback flag and marked
substream pointer.
One note here is that it cares *current* startup() only now.
but we might want to check *whole* marked substream in the future.
This patch is using macro named "push/pop", so that it can be easily
update.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87lfgubwoc.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-09-28 08:00:40 +08:00
|
|
|
struct snd_pcm_substream *substream, int rollback);
|
2019-07-22 09:34:29 +08:00
|
|
|
void snd_soc_dai_suspend(struct snd_soc_dai *dai);
|
2019-07-22 09:34:43 +08:00
|
|
|
void snd_soc_dai_resume(struct snd_soc_dai *dai);
|
2019-07-22 09:35:29 +08:00
|
|
|
int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
|
|
|
|
struct snd_soc_pcm_runtime *rtd, int num);
|
2019-07-22 09:36:16 +08:00
|
|
|
bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int stream);
|
2020-07-08 05:04:37 +08:00
|
|
|
void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link);
|
2020-05-15 08:46:27 +08:00
|
|
|
void snd_soc_dai_action(struct snd_soc_dai *dai,
|
|
|
|
int stream, int action);
|
|
|
|
static inline void snd_soc_dai_activate(struct snd_soc_dai *dai,
|
|
|
|
int stream)
|
|
|
|
{
|
|
|
|
snd_soc_dai_action(dai, stream, 1);
|
|
|
|
}
|
|
|
|
static inline void snd_soc_dai_deactivate(struct snd_soc_dai *dai,
|
|
|
|
int stream)
|
|
|
|
{
|
|
|
|
snd_soc_dai_action(dai, stream, -1);
|
|
|
|
}
|
2020-05-15 08:46:37 +08:00
|
|
|
int snd_soc_dai_active(struct snd_soc_dai *dai);
|
2019-07-22 09:33:04 +08:00
|
|
|
|
2020-04-24 07:15:15 +08:00
|
|
|
int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order);
|
2020-04-24 07:15:20 +08:00
|
|
|
int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order);
|
2020-04-24 07:14:48 +08:00
|
|
|
int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd);
|
2020-04-24 07:14:53 +08:00
|
|
|
int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream);
|
ASoC: soc-pcm: care trigger rollback
soc_pcm_trigger() calls DAI/Component/Link trigger,
but some of them might be failed.
static int soc_pcm_trigger(...)
{
...
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = snd_soc_link_trigger(substream, cmd);
if (ret < 0)
break;
(*) ret = snd_soc_pcm_component_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_pcm_dai_trigger(substream, cmd);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = snd_soc_pcm_dai_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_pcm_component_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_link_trigger(substream, cmd);
break;
}
...
}
For example, if soc_pcm_trigger() failed at (*) point,
we need to rollback previous succeeded trigger.
This patch adds trigger mark for DAI/Component/Link,
and do STOP if START/RESUME/PAUSE_RELEASE were failed.
Because it need to use new rollback parameter,
we need to modify DAI/Component/Link trigger functions in the same time.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87a6uycssd.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-12-01 07:51:33 +08:00
|
|
|
int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
|
|
|
int rollback);
|
2020-04-24 07:15:09 +08:00
|
|
|
int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
|
|
|
|
int cmd);
|
2021-11-16 15:45:12 +08:00
|
|
|
void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
|
|
|
|
snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay);
|
2020-04-24 07:14:48 +08:00
|
|
|
|
2020-04-24 07:15:24 +08:00
|
|
|
int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream);
|
2020-04-24 07:15:28 +08:00
|
|
|
void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
|
2020-11-19 07:50:04 +08:00
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
int rollback);
|
2020-04-24 07:15:32 +08:00
|
|
|
int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream, int cmd);
|
2020-04-24 07:15:36 +08:00
|
|
|
int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
struct snd_compr_params *params);
|
2020-04-24 07:15:40 +08:00
|
|
|
int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
struct snd_codec *params);
|
2020-04-24 07:15:45 +08:00
|
|
|
int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
size_t bytes);
|
2020-04-24 07:15:49 +08:00
|
|
|
int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
struct snd_compr_tstamp *tstamp);
|
2020-04-24 07:15:54 +08:00
|
|
|
int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
struct snd_compr_metadata *metadata);
|
2020-04-24 07:15:59 +08:00
|
|
|
int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
|
|
|
|
struct snd_compr_stream *cstream,
|
|
|
|
struct snd_compr_metadata *metadata);
|
2020-04-24 07:15:24 +08:00
|
|
|
|
2023-07-10 09:19:53 +08:00
|
|
|
const char *snd_soc_dai_name_get(struct snd_soc_dai *dai);
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
struct snd_soc_dai_ops {
|
2023-08-09 06:54:50 +08:00
|
|
|
/* DAI driver callbacks */
|
|
|
|
int (*probe)(struct snd_soc_dai *dai);
|
|
|
|
int (*remove)(struct snd_soc_dai *dai);
|
|
|
|
/* compress dai */
|
|
|
|
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
|
|
|
|
/* Optional Callback used at pcm creation*/
|
|
|
|
int (*pcm_new)(struct snd_soc_pcm_runtime *rtd,
|
|
|
|
struct snd_soc_dai *dai);
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/*
|
|
|
|
* DAI clocking configuration, all optional.
|
|
|
|
* Called by soc_card drivers, normally in their hw_params.
|
|
|
|
*/
|
|
|
|
int (*set_sysclk)(struct snd_soc_dai *dai,
|
|
|
|
int clk_id, unsigned int freq, int dir);
|
2009-09-06 01:52:16 +08:00
|
|
|
int (*set_pll)(struct snd_soc_dai *dai, int pll_id, int source,
|
|
|
|
unsigned int freq_in, unsigned int freq_out);
|
2008-07-23 21:03:07 +08:00
|
|
|
int (*set_clkdiv)(struct snd_soc_dai *dai, int div_id, int div);
|
2013-09-16 20:01:46 +08:00
|
|
|
int (*set_bclk_ratio)(struct snd_soc_dai *dai, unsigned int ratio);
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* DAI format configuration
|
|
|
|
* Called by soc_card drivers, normally in their hw_params.
|
|
|
|
*/
|
|
|
|
int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt);
|
2014-03-21 14:17:12 +08:00
|
|
|
int (*xlate_tdm_slot_mask)(unsigned int slots,
|
2014-02-14 09:34:35 +08:00
|
|
|
unsigned int *tx_mask, unsigned int *rx_mask);
|
2008-07-23 21:03:07 +08:00
|
|
|
int (*set_tdm_slot)(struct snd_soc_dai *dai,
|
2009-06-16 08:44:31 +08:00
|
|
|
unsigned int tx_mask, unsigned int rx_mask,
|
|
|
|
int slots, int slot_width);
|
2009-09-12 01:16:29 +08:00
|
|
|
int (*set_channel_map)(struct snd_soc_dai *dai,
|
|
|
|
unsigned int tx_num, unsigned int *tx_slot,
|
|
|
|
unsigned int rx_num, unsigned int *rx_slot);
|
2018-07-23 23:54:03 +08:00
|
|
|
int (*get_channel_map)(struct snd_soc_dai *dai,
|
|
|
|
unsigned int *tx_num, unsigned int *tx_slot,
|
|
|
|
unsigned int *rx_num, unsigned int *rx_slot);
|
2008-07-23 21:03:07 +08:00
|
|
|
int (*set_tristate)(struct snd_soc_dai *dai, int tristate);
|
|
|
|
|
2021-12-24 10:10:31 +08:00
|
|
|
int (*set_stream)(struct snd_soc_dai *dai,
|
|
|
|
void *stream, int direction);
|
|
|
|
void *(*get_stream)(struct snd_soc_dai *dai, int direction);
|
2020-02-26 01:00:40 +08:00
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/*
|
|
|
|
* DAI digital mute - optional.
|
|
|
|
* Called by soc-core to minimise any pops.
|
|
|
|
*/
|
2013-02-06 23:44:07 +08:00
|
|
|
int (*mute_stream)(struct snd_soc_dai *dai, int mute, int stream);
|
2008-11-19 06:11:38 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* ALSA PCM audio operations - all optional.
|
|
|
|
* Called by soc-core during audio PCM operations.
|
|
|
|
*/
|
|
|
|
int (*startup)(struct snd_pcm_substream *,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
void (*shutdown)(struct snd_pcm_substream *,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
int (*hw_params)(struct snd_pcm_substream *,
|
|
|
|
struct snd_pcm_hw_params *, struct snd_soc_dai *);
|
|
|
|
int (*hw_free)(struct snd_pcm_substream *,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
int (*prepare)(struct snd_pcm_substream *,
|
|
|
|
struct snd_soc_dai *);
|
2013-10-11 18:11:02 +08:00
|
|
|
/*
|
|
|
|
* NOTE: Commands passed to the trigger function are not necessarily
|
|
|
|
* compatible with the current state of the dai. For example this
|
|
|
|
* sequence of commands is possible: START STOP STOP.
|
|
|
|
* So do not unconditionally use refcounting functions in the trigger
|
|
|
|
* function, e.g. clk_enable/disable.
|
|
|
|
*/
|
2008-11-19 06:11:38 +08:00
|
|
|
int (*trigger)(struct snd_pcm_substream *, int,
|
|
|
|
struct snd_soc_dai *);
|
2012-04-25 19:12:52 +08:00
|
|
|
int (*bespoke_trigger)(struct snd_pcm_substream *, int,
|
|
|
|
struct snd_soc_dai *);
|
2010-03-03 21:08:07 +08:00
|
|
|
/*
|
|
|
|
* For hardware based FIFO caused delay reporting.
|
|
|
|
* Optional.
|
|
|
|
*/
|
|
|
|
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
|
|
|
|
struct snd_soc_dai *);
|
2020-07-09 09:55:41 +08:00
|
|
|
|
ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
ASoC is using dai_link which specify DAI format (= dai_link->dai_fmt),
and it is selected by "Sound Card" driver in corrent implementation.
In other words, Sound Card *needs* to setup it.
But, it should be possible to automatically selected from CPU and
Codec driver settings.
This patch adds new .auto_selectable_formats support
at snd_soc_dai_ops.
By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had it.
Automatically selectable *field* is depends on each drivers.
For example, some driver want to select format "automatically",
but want to select other fields "manually", because of complex limitation.
Or other example, in case of both CPU and Codec are possible to be
clock provider, but the quality was different.
In these case, user need/want to *manually* select each fields
from Sound Card driver.
This .auto_selectable_formats can set priority.
For example, no limitaion format can be HI priority,
supported but has picky limitation format can be next priority, etc.
It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver automatically
if all drivers have .auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.
Link: https://lore.kernel.org/r/871rb3hypy.wl-kuninori.morimoto.gx@renesas.com
Link: https://lore.kernel.org/r/871racbx0w.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87h7ionc8s.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2021-05-27 10:26:12 +08:00
|
|
|
/*
|
|
|
|
* Format list for auto selection.
|
|
|
|
* Format will be increased if priority format was
|
|
|
|
* not selected.
|
|
|
|
* see
|
|
|
|
* snd_soc_dai_get_fmt()
|
|
|
|
*/
|
|
|
|
u64 *auto_selectable_formats;
|
|
|
|
int num_auto_selectable_formats;
|
|
|
|
|
2023-08-09 06:54:50 +08:00
|
|
|
/* probe ordering - for components with runtime dependencies */
|
|
|
|
int probe_order;
|
|
|
|
int remove_order;
|
|
|
|
|
2020-07-09 09:55:41 +08:00
|
|
|
/* bit field */
|
|
|
|
unsigned int no_capture_mute:1;
|
2008-07-23 21:03:07 +08:00
|
|
|
};
|
|
|
|
|
2016-11-13 14:40:02 +08:00
|
|
|
struct snd_soc_cdai_ops {
|
|
|
|
/*
|
|
|
|
* for compress ops
|
|
|
|
*/
|
|
|
|
int (*startup)(struct snd_compr_stream *,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
int (*shutdown)(struct snd_compr_stream *,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
int (*set_params)(struct snd_compr_stream *,
|
|
|
|
struct snd_compr_params *, struct snd_soc_dai *);
|
|
|
|
int (*get_params)(struct snd_compr_stream *,
|
|
|
|
struct snd_codec *, struct snd_soc_dai *);
|
|
|
|
int (*set_metadata)(struct snd_compr_stream *,
|
|
|
|
struct snd_compr_metadata *, struct snd_soc_dai *);
|
|
|
|
int (*get_metadata)(struct snd_compr_stream *,
|
|
|
|
struct snd_compr_metadata *, struct snd_soc_dai *);
|
|
|
|
int (*trigger)(struct snd_compr_stream *, int,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
int (*pointer)(struct snd_compr_stream *,
|
|
|
|
struct snd_compr_tstamp *, struct snd_soc_dai *);
|
|
|
|
int (*ack)(struct snd_compr_stream *, size_t,
|
|
|
|
struct snd_soc_dai *);
|
|
|
|
};
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
/*
|
2010-03-18 04:15:21 +08:00
|
|
|
* Digital Audio Interface Driver.
|
2008-07-23 21:03:07 +08:00
|
|
|
*
|
2010-03-18 04:15:21 +08:00
|
|
|
* Describes the Digital Audio Interface in terms of its ALSA, DAI and AC97
|
|
|
|
* operations and capabilities. Codec and platform drivers will register this
|
|
|
|
* structure for every DAI they have.
|
|
|
|
*
|
|
|
|
* This structure covers the clocking, formating and ALSA operations for each
|
|
|
|
* interface.
|
2008-07-23 21:03:07 +08:00
|
|
|
*/
|
2010-03-18 04:15:21 +08:00
|
|
|
struct snd_soc_dai_driver {
|
2008-07-23 21:03:07 +08:00
|
|
|
/* DAI description */
|
2010-03-18 04:15:21 +08:00
|
|
|
const char *name;
|
2008-07-23 21:03:07 +08:00
|
|
|
unsigned int id;
|
2012-05-02 03:03:32 +08:00
|
|
|
unsigned int base;
|
2015-12-31 16:40:43 +08:00
|
|
|
struct snd_soc_dobj dobj;
|
ASoC: soc-core.c: enable multi Component
Current ASoC Card is using dlc (snd_soc_dai_link_component) to find
target DAI / Component to be used.
Current dlc has below 3 items to identify DAI / Component
(a) name for Component
(b) of_node for Component
(c) dai_name for DAI
(a) or (b) is used to identify target Component, and (c) is used
to identify DAI.
One of the biggest issue on it today is dlc needs "name matching"
for "dai_name" (c).
It was not a big deal when we were using platform_device, because we
could specify nessesary "dai_name" via its platform_data.
But we need to find DAI name pointer from whole registered datas and/or
each related driver somehow in case of DT, because we can't specify it.
Therefore, Card driver parses DT and assumes the DAI, and find its name
pointer. How to assume is based on each Component and/or Card.
Next biggest issue is Component node (a)/(b).
Basically, Component is registered when CPU/Codec driver was
probed() (X). Here, 1 Component is possible to have some DAIs.
int xxx_probe(struct platform_device *pdev)
{
...
(X) ret = devm_snd_soc_register_component(pdev->dev,
&component_driver,
&dai_driver, dai_driver_num);
...
}
The image of each data will be like below.
One note here is "driver" is included for later explanation.
+-driver------+
|+-component-+|
|| dai0||
|| dai1||
|| ...||
|+-----------+|
+-------------+
The point here is 1 driver has 1 Component, because basically driver
calles snd_soc_register_component() (= X) once.
Here is the very basic CPU/Codec connection image.
HW image SW image
+-- Board ------------+ +-card--------------------------+
|+-----+ +------+| |+-driver------+ +-driver------+|
|| CPU | <--> |CodecA|| ||+-component-+| |+-component-+||
|+-----+ +------+| ||| dai|<=>|dai |||
+---------------------+ ||+-----------+| |+-----------+||
|+-------------+ +-------------+|
+-------------------------------+
It will be very complex if it has multi DAIs.
Here is intuitive easy to understandable HW / SW example.
HW image SW image
+-- Board ---------------+ +-card--------------------------+
|+--------+ +------+| |+-driver------+ +-driver------+|
|| CPU ch0| <--> |CodecA|| ||+-component-+| |+-component-+||
|| | +------+| ||| ch0 dai|<=>|dai |||
|| | +------+| ||| || |+-----------+||
|| ch1| <--> |CodecB|| ||| || +-------------+|
|+--------+ +------+| ||| || +-driver------+|
+------------------------+ ||| || |+-component-+||
||| ch1 dai|<=>|dai |||
||+-----------+| |+-----------+||
|+-------------+ +-------------+|
+-------------------------------+
It will be handled as multi interface as "one Card".
card0,0: CPU-ch0 - CodecA
card0,1: CPU-ch1 - CodecB
^
But, here is the HW image example which will be more complex
+-- Basic Board ---------+
|+--------+ +------+|
|| CPU ch0| <--> |CodecA||
|| ch1| <-+ +------+|
|+--------+ | |
+-------------|----------+
+-- expansion board -----+
| | +------+|
| +->|CodecB||
| +------+|
+------------------------+
We intuitively think we want to handle these as "2 Sound Cards".
card0,0: CPU-ch0 - CodecA
card1,0: CPU-ch1 - CodecB
^
But below image which we can register today doesn't allow it,
because the same Component will be connected to both Card0/1,
but it will be rejected by (Z).
+-driver------+
|+-component-+|
+-card0-------------------------+
||| || +-driver------+|
||| || |+-component-+||
||| ch0 dai|<=>|dai |||
||| || |+-----------+||
||| || +-------------+|
+-------------------------------+
|| ||
+-card1-------------------------+
||| || +-driver------+|
||| || |+-component-+||
||| ch1 dai|<=>|dai |||
||| || |+-----------+||
||| || +-------------+|
+-------------------------------+
|+-----------+|
+-------------+
static int soc_probe_component()
{
...
if (component->card) {
(Z) if (component->card != card) {
dev_err(component->dev, ...);
return -ENODEV;
}
return 0;
}
...
}
So, how about to call snd_soc_register_component() (= X) multiple times
on probe() to avoid buplicated component->card limitation, to be like
below ?
+-driver------+
+-card0-------------------------+
|| | +-driver------+|
||+-component-+| |+-component-+||
||| ch0 dai|<=>|dai |||
||+-----------+| |+-----------+||
|| | +-------------+|
+-------------------------------+
| |
+-card1-------------------------+
|| | +-driver------+|
||+-component-+| |+-component-+||
||| ch1 dai|<=>|dai |||
||+-----------+| |+-----------+||
|| | +-------------+|
+-------------------------------+
+-------------+
Yes, looks good. But unfortunately it doesn't help us for now.
Let's see soc_component_to_node() and snd_soc_is_matching_component()
static struct device_node
*soc_component_to_node(struct snd_soc_component *component)
{
...
(A) of_node = component->dev->of_node;
...
}
static int snd_soc_is_matching_component(...)
{
...
(B) if (dlc->of_node && component_of_node != dlc->of_node)
...
}
dlc checkes "of_node" to identify target component (B),
but this "of_node" came from component->dev (A) which is added
by snd_soc_register_component() (X) on probe().
This means we can have different "component->card", but have same
"component->dev" in this case.
Even though we calls snd_soc_register_component() (= X) multiple times,
all Components have same driver's dev, thus it is impossible to
identified the Component.
And if it was impossible to identify Component, it is impossible to
identify DAI on current implementation.
So, how to handle above complex HW image today is 2 patterns.
One is handles it as "1 big sound card".
The SW image is like below.
SW image
+-card--------------------------+
|+-driver------+ +-driver------+|
||+-component-+| |+-component-+||
||| ch0 dai|<=>|dai |||
||| || |+-----------+||
||| || +-------------+|
||| || +-driver------+|
||| || |+-component-+||
||| ch1 dai|<->|dai |||
||+-----------+| |+-----------+||
|+-------------+ +-------------+|
+-------------------------------+
But the problem is not intuitive.
We want to handle it as "2 Cards".
2nd pattern is like below.
SW image
+-card0-------------------------+
|+-driver------+ +-driver------+|
||+-component-+| |+-component-+||
||| ch0 dai|<=>|dai |||
||+-----------+| |+-----------+||
|+-------------+ +-------------+|
+-------------------------------+
+-card1-------------------------+
|+-driver------+ +-driver------+|
||+-component-+| |+-component-+||
||| ch1 dai|<=>|dai |||
||+-----------+| |+-----------+||
|+-------------+ +-------------+|
+-------------------------------+
It handles as "2 Cards", but CPU part needs to be probed as 2 drivers.
It is also not intuitive.
To solve this issue, we need to have multi Component support.
In current implementation, we need to identify Component first
to identify DAI, and it is using name matching to identify DAI.
But how about to be enable to directly identify DAI by unique way
instead of name matching ? In such case, we can directly identify DAI,
then it can identify Component from DAI.
For example Simple-Card / Audio-Graph-Card case, it is specifying DAI
via its node.
Simple-Card
sound-dai = <&cpu-sound>;
Audio-Graph-Card
dais = <&cpu-sound>;
If each CPU/Codec driver keeps this property when probing,
we can identify DAI directly from Card.
Being able to identify DAI directly means being able to identify its
Component as well even though Component has same dev (= B).
This patch adds new "dai_node" for it.
To keeping compatibility, it checks "dai_node" first if it has,
otherwise, use existing method (name matching).
Link: https://lore.kernel.org/r/87fskz5yrr.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87fs5wo94v.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2023-07-10 09:20:00 +08:00
|
|
|
struct of_phandle_args *dai_args;
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/* ops */
|
2010-12-03 00:10:09 +08:00
|
|
|
const struct snd_soc_dai_ops *ops;
|
2016-11-13 14:40:02 +08:00
|
|
|
const struct snd_soc_cdai_ops *cops;
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/* DAI capabilities */
|
|
|
|
struct snd_soc_pcm_stream capture;
|
|
|
|
struct snd_soc_pcm_stream playback;
|
2021-01-15 12:52:54 +08:00
|
|
|
unsigned int symmetric_rate:1;
|
2013-11-13 18:56:24 +08:00
|
|
|
unsigned int symmetric_channels:1;
|
2021-01-15 12:52:54 +08:00
|
|
|
unsigned int symmetric_sample_bits:1;
|
2010-03-18 04:15:21 +08:00
|
|
|
};
|
|
|
|
|
2023-01-31 10:02:04 +08:00
|
|
|
/* for Playback/Capture */
|
|
|
|
struct snd_soc_dai_stream {
|
|
|
|
struct snd_soc_dapm_widget *widget;
|
|
|
|
|
|
|
|
unsigned int active; /* usage count */
|
|
|
|
unsigned int tdm_mask; /* CODEC TDM slot masks and params (for fixup) */
|
|
|
|
|
|
|
|
void *dma_data; /* DAI DMA data */
|
|
|
|
};
|
|
|
|
|
2010-03-18 04:15:21 +08:00
|
|
|
/*
|
|
|
|
* Digital Audio Interface runtime data.
|
|
|
|
*
|
|
|
|
* Holds runtime data for a DAI.
|
|
|
|
*/
|
|
|
|
struct snd_soc_dai {
|
|
|
|
const char *name;
|
|
|
|
int id;
|
|
|
|
struct device *dev;
|
|
|
|
|
|
|
|
/* driver ops */
|
|
|
|
struct snd_soc_dai_driver *driver;
|
2008-07-23 21:03:07 +08:00
|
|
|
|
|
|
|
/* DAI runtime info */
|
2023-01-31 10:02:04 +08:00
|
|
|
struct snd_soc_dai_stream stream[SNDRV_PCM_STREAM_LAST + 1];
|
2008-07-23 21:03:07 +08:00
|
|
|
|
2011-08-29 17:15:14 +08:00
|
|
|
/* Symmetry data - only valid if symmetry is being enforced */
|
|
|
|
unsigned int rate;
|
2013-11-13 18:56:24 +08:00
|
|
|
unsigned int channels;
|
|
|
|
unsigned int sample_bits;
|
2011-08-29 17:15:14 +08:00
|
|
|
|
2010-03-18 04:15:21 +08:00
|
|
|
/* parent platform/codec */
|
2014-03-05 20:17:46 +08:00
|
|
|
struct snd_soc_component *component;
|
2012-03-03 00:18:30 +08:00
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
struct list_head list;
|
2020-02-10 11:14:33 +08:00
|
|
|
|
ASoC: soc-dai: add mark for snd_soc_dai_startup/shutdown()
soc_pcm_open() does rollback when failed (A),
but, it is almost same as soc_pcm_close().
static int soc_pcm_open(xxx)
{
...
if (ret < 0)
goto xxx_err;
...
return 0;
^ config_err:
| ...
| rtd_startup_err:
(A) ...
| component_err:
| ...
v return ret;
}
The difference is
soc_pcm_close() is for all dai/component/substream,
rollback is for succeeded part only.
This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_close() and rollback.
Now, soc_pcm_open/close() are handling
=> 1) snd_soc_dai_startup/shutdown()
2) snd_soc_link_startup/shutdown()
3) snd_soc_component_module_get/put()
4) snd_soc_component_open/close()
5) pm_runtime_put/get()
This patch is for 1) snd_soc_dai_startup/shutdown().
The idea of having bit-flag or counter is not enough for this purpose.
For example if one DAI is used for 2xPlaybacks for some reasons,
and if 1st Playback was succeeded but 2nd Playback was failed,
2nd Playback rollback doesn't need to call shutdown.
But it has succeeded bit-flag or counter via 1st Playback,
thus, 2nd Playback rollback will call unneeded shutdown.
And 1st Playback's necessary shutdown will not be called,
because bit-flag or counter was cleared by wrong 2nd Playback rollback.
To avoid such case, this patch marks substream pointer when startup() was
succeeded. If rollback needed, it will check rollback flag and marked
substream pointer.
One note here is that it cares *current* startup() only now.
but we might want to check *whole* marked substream in the future.
This patch is using macro named "push/pop", so that it can be easily
update.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87lfgubwoc.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-09-28 08:00:40 +08:00
|
|
|
/* function mark */
|
|
|
|
struct snd_pcm_substream *mark_startup;
|
ASoC: soc-dai: add mark for snd_soc_dai_hw_params/free()
soc_pcm_hw_params() does rollback when failed (A),
but, it is almost same as soc_pcm_hw_free().
static int soc_pcm_hw_params(xxx)
{
...
if (ret < 0)
goto xxx_err;
...
return ret;
^ component_err:
| ...
| interface_err:
(A) ...
| codec_err:
| ...
v return ret;
}
The difference is
soc_pcm_hw_free() is for all dai/component/substream,
rollback is for succeeded part only.
This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_hw_free() and rollback.
Now, soc_pcm_hw_params/free() are handling
1) snd_soc_link_hw_params/free()
2) snd_soc_pcm_component_hw_params/free()
=> 3) snd_soc_dai_hw_params/free()
This patch is for 3) snd_soc_dai_hw_params/free().
The idea of having bit-flag or counter is not enough for this purpose.
For example if one DAI is used for 2xPlaybacks for some reasons,
and if 1st Playback was succeeded but 2nd Playback was failed,
2nd Playback rollback doesn't need to call shutdown.
But it has succeeded bit-flag or counter via 1st Playback,
thus, 2nd Playback rollback will call unneeded shutdown.
And 1st Playback's necessary shutdown will not be called,
because bit-flag or counter was cleared by wrong 2nd Playback rollback.
To avoid such case, this patch marks substream pointer when hw_params() was
succeeded. If rollback needed, it will check rollback flag and marked
substream pointer.
One note here is that it cares *previous* hw_params() only now,
but we might want to check *whole* marked substream in the future.
This patch is using macro named "push/pop", so that it can be easily
update.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87imbxgqai.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-09-29 12:31:53 +08:00
|
|
|
struct snd_pcm_substream *mark_hw_params;
|
ASoC: soc-pcm: care trigger rollback
soc_pcm_trigger() calls DAI/Component/Link trigger,
but some of them might be failed.
static int soc_pcm_trigger(...)
{
...
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
ret = snd_soc_link_trigger(substream, cmd);
if (ret < 0)
break;
(*) ret = snd_soc_pcm_component_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_pcm_dai_trigger(substream, cmd);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = snd_soc_pcm_dai_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_pcm_component_trigger(substream, cmd);
if (ret < 0)
break;
ret = snd_soc_link_trigger(substream, cmd);
break;
}
...
}
For example, if soc_pcm_trigger() failed at (*) point,
we need to rollback previous succeeded trigger.
This patch adds trigger mark for DAI/Component/Link,
and do STOP if START/RESUME/PAUSE_RELEASE were failed.
Because it need to use new rollback parameter,
we need to modify DAI/Component/Link trigger functions in the same time.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87a6uycssd.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-12-01 07:51:33 +08:00
|
|
|
struct snd_pcm_substream *mark_trigger;
|
2020-11-19 07:50:04 +08:00
|
|
|
struct snd_compr_stream *mark_compr_startup;
|
ASoC: soc-dai: add mark for snd_soc_dai_startup/shutdown()
soc_pcm_open() does rollback when failed (A),
but, it is almost same as soc_pcm_close().
static int soc_pcm_open(xxx)
{
...
if (ret < 0)
goto xxx_err;
...
return 0;
^ config_err:
| ...
| rtd_startup_err:
(A) ...
| component_err:
| ...
v return ret;
}
The difference is
soc_pcm_close() is for all dai/component/substream,
rollback is for succeeded part only.
This kind of duplicated code can be a hotbed of bugs,
thus, we want to share soc_pcm_close() and rollback.
Now, soc_pcm_open/close() are handling
=> 1) snd_soc_dai_startup/shutdown()
2) snd_soc_link_startup/shutdown()
3) snd_soc_component_module_get/put()
4) snd_soc_component_open/close()
5) pm_runtime_put/get()
This patch is for 1) snd_soc_dai_startup/shutdown().
The idea of having bit-flag or counter is not enough for this purpose.
For example if one DAI is used for 2xPlaybacks for some reasons,
and if 1st Playback was succeeded but 2nd Playback was failed,
2nd Playback rollback doesn't need to call shutdown.
But it has succeeded bit-flag or counter via 1st Playback,
thus, 2nd Playback rollback will call unneeded shutdown.
And 1st Playback's necessary shutdown will not be called,
because bit-flag or counter was cleared by wrong 2nd Playback rollback.
To avoid such case, this patch marks substream pointer when startup() was
succeeded. If rollback needed, it will check rollback flag and marked
substream pointer.
One note here is that it cares *current* startup() only now.
but we might want to check *whole* marked substream in the future.
This patch is using macro named "push/pop", so that it can be easily
update.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Link: https://lore.kernel.org/r/87lfgubwoc.wl-kuninori.morimoto.gx@renesas.com
Signed-off-by: Mark Brown <broonie@kernel.org>
2020-09-28 08:00:40 +08:00
|
|
|
|
2020-02-10 11:14:33 +08:00
|
|
|
/* bit field */
|
|
|
|
unsigned int probed:1;
|
2008-07-23 21:03:07 +08:00
|
|
|
};
|
|
|
|
|
2020-02-19 14:56:30 +08:00
|
|
|
static inline struct snd_soc_pcm_stream *
|
|
|
|
snd_soc_dai_get_pcm_stream(const struct snd_soc_dai *dai, int stream)
|
|
|
|
{
|
|
|
|
return (stream == SNDRV_PCM_STREAM_PLAYBACK) ?
|
|
|
|
&dai->driver->playback : &dai->driver->capture;
|
|
|
|
}
|
|
|
|
|
2023-01-31 09:59:17 +08:00
|
|
|
#define snd_soc_dai_get_widget_playback(dai) snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
|
#define snd_soc_dai_get_widget_capture(dai) snd_soc_dai_get_widget(dai, SNDRV_PCM_STREAM_CAPTURE)
|
2020-02-19 14:56:41 +08:00
|
|
|
static inline
|
2023-01-31 09:58:50 +08:00
|
|
|
struct snd_soc_dapm_widget *snd_soc_dai_get_widget(struct snd_soc_dai *dai, int stream)
|
2020-02-19 14:56:41 +08:00
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
return dai->stream[stream].widget;
|
2020-02-19 14:56:41 +08:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:59:17 +08:00
|
|
|
#define snd_soc_dai_set_widget_playback(dai, widget) snd_soc_dai_set_widget(dai, SNDRV_PCM_STREAM_PLAYBACK, widget)
|
|
|
|
#define snd_soc_dai_set_widget_capture(dai, widget) snd_soc_dai_set_widget(dai, SNDRV_PCM_STREAM_CAPTURE, widget)
|
2023-01-31 09:58:50 +08:00
|
|
|
static inline
|
|
|
|
void snd_soc_dai_set_widget(struct snd_soc_dai *dai, int stream, struct snd_soc_dapm_widget *widget)
|
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
dai->stream[stream].widget = widget;
|
2023-01-31 09:58:50 +08:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:58:58 +08:00
|
|
|
#define snd_soc_dai_dma_data_get_playback(dai) snd_soc_dai_dma_data_get(dai, SNDRV_PCM_STREAM_PLAYBACK)
|
|
|
|
#define snd_soc_dai_dma_data_get_capture(dai) snd_soc_dai_dma_data_get(dai, SNDRV_PCM_STREAM_CAPTURE)
|
|
|
|
#define snd_soc_dai_get_dma_data(dai, ss) snd_soc_dai_dma_data_get(dai, ss->stream)
|
|
|
|
static inline void *snd_soc_dai_dma_data_get(const struct snd_soc_dai *dai, int stream)
|
2010-03-19 22:52:55 +08:00
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
return dai->stream[stream].dma_data;
|
2010-03-19 22:52:55 +08:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:58:58 +08:00
|
|
|
#define snd_soc_dai_dma_data_set_playback(dai, data) snd_soc_dai_dma_data_set(dai, SNDRV_PCM_STREAM_PLAYBACK, data)
|
|
|
|
#define snd_soc_dai_dma_data_set_capture(dai, data) snd_soc_dai_dma_data_set(dai, SNDRV_PCM_STREAM_CAPTURE, data)
|
|
|
|
#define snd_soc_dai_set_dma_data(dai, ss, data) snd_soc_dai_dma_data_set(dai, ss->stream, data)
|
|
|
|
static inline void snd_soc_dai_dma_data_set(struct snd_soc_dai *dai, int stream, void *data)
|
2010-03-19 22:52:55 +08:00
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
dai->stream[stream].dma_data = data;
|
2010-03-18 04:15:21 +08:00
|
|
|
}
|
|
|
|
|
2023-01-31 10:02:04 +08:00
|
|
|
static inline void snd_soc_dai_init_dma_data(struct snd_soc_dai *dai, void *playback, void *capture)
|
2013-10-18 04:13:19 +08:00
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
snd_soc_dai_dma_data_set_playback(dai, playback);
|
|
|
|
snd_soc_dai_dma_data_set_capture(dai, capture);
|
2013-10-18 04:13:19 +08:00
|
|
|
}
|
|
|
|
|
2023-01-31 09:59:07 +08:00
|
|
|
static inline unsigned int snd_soc_dai_tdm_mask_get(struct snd_soc_dai *dai, int stream)
|
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
return dai->stream[stream].tdm_mask;
|
2023-01-31 09:59:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline void snd_soc_dai_tdm_mask_set(struct snd_soc_dai *dai, int stream,
|
|
|
|
unsigned int tdm_mask)
|
|
|
|
{
|
2023-01-31 10:02:04 +08:00
|
|
|
dai->stream[stream].tdm_mask = tdm_mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int snd_soc_dai_stream_active(struct snd_soc_dai *dai, int stream)
|
|
|
|
{
|
|
|
|
/* see snd_soc_dai_action() for setup */
|
|
|
|
return dai->stream[stream].active;
|
2023-01-31 09:59:07 +08:00
|
|
|
}
|
|
|
|
|
2010-03-18 04:15:21 +08:00
|
|
|
static inline void snd_soc_dai_set_drvdata(struct snd_soc_dai *dai,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
dev_set_drvdata(dai->dev, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void *snd_soc_dai_get_drvdata(struct snd_soc_dai *dai)
|
|
|
|
{
|
|
|
|
return dev_get_drvdata(dai->dev);
|
2010-03-19 22:52:55 +08:00
|
|
|
}
|
|
|
|
|
2018-04-26 21:08:38 +08:00
|
|
|
/**
|
2021-12-24 10:10:31 +08:00
|
|
|
* snd_soc_dai_set_stream() - Configures a DAI for stream operation
|
2018-04-26 21:08:38 +08:00
|
|
|
* @dai: DAI
|
2021-12-24 10:10:31 +08:00
|
|
|
* @stream: STREAM (opaque structure depending on DAI type)
|
2018-04-26 21:08:38 +08:00
|
|
|
* @direction: Stream direction(Playback/Capture)
|
2021-12-24 10:10:31 +08:00
|
|
|
* Some subsystems, such as SoundWire, don't have a notion of direction and we reuse
|
2018-04-26 21:08:38 +08:00
|
|
|
* the ASoC stream direction to configure sink/source ports.
|
|
|
|
* Playback maps to source ports and Capture for sink ports.
|
|
|
|
*
|
|
|
|
* This should be invoked with NULL to clear the stream set previously.
|
|
|
|
* Returns 0 on success, a negative error code otherwise.
|
|
|
|
*/
|
2021-12-24 10:10:31 +08:00
|
|
|
static inline int snd_soc_dai_set_stream(struct snd_soc_dai *dai,
|
|
|
|
void *stream, int direction)
|
2018-04-26 21:08:38 +08:00
|
|
|
{
|
2021-12-24 10:10:31 +08:00
|
|
|
if (dai->driver->ops->set_stream)
|
|
|
|
return dai->driver->ops->set_stream(dai, stream, direction);
|
2018-04-26 21:08:38 +08:00
|
|
|
else
|
|
|
|
return -ENOTSUPP;
|
|
|
|
}
|
|
|
|
|
2020-02-26 01:00:40 +08:00
|
|
|
/**
|
2021-12-24 10:10:31 +08:00
|
|
|
* snd_soc_dai_get_stream() - Retrieves stream from DAI
|
2020-02-26 01:00:40 +08:00
|
|
|
* @dai: DAI
|
|
|
|
* @direction: Stream direction(Playback/Capture)
|
|
|
|
*
|
|
|
|
* This routine only retrieves that was previously configured
|
2021-12-24 10:10:31 +08:00
|
|
|
* with snd_soc_dai_get_stream()
|
2020-02-26 01:00:40 +08:00
|
|
|
*
|
2020-09-05 02:28:52 +08:00
|
|
|
* Returns pointer to stream or an ERR_PTR value, e.g.
|
|
|
|
* ERR_PTR(-ENOTSUPP) if callback is not supported;
|
2020-02-26 01:00:40 +08:00
|
|
|
*/
|
2021-12-24 10:10:31 +08:00
|
|
|
static inline void *snd_soc_dai_get_stream(struct snd_soc_dai *dai,
|
|
|
|
int direction)
|
2020-02-26 01:00:40 +08:00
|
|
|
{
|
2021-12-24 10:10:31 +08:00
|
|
|
if (dai->driver->ops->get_stream)
|
|
|
|
return dai->driver->ops->get_stream(dai, direction);
|
2020-02-26 01:00:40 +08:00
|
|
|
else
|
2020-03-16 23:11:10 +08:00
|
|
|
return ERR_PTR(-ENOTSUPP);
|
2020-02-26 01:00:40 +08:00
|
|
|
}
|
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
#endif
|