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
|
|
|
|
2008-07-23 21:03:07 +08:00
|
|
|
struct snd_soc_dai_ops {
|
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
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;
|
2008-07-23 21:03:07 +08:00
|
|
|
|
2010-03-18 04:15:21 +08:00
|
|
|
/* DAI driver callbacks */
|
|
|
|
int (*probe)(struct snd_soc_dai *dai);
|
|
|
|
int (*remove)(struct snd_soc_dai *dai);
|
2012-08-16 19:40:40 +08:00
|
|
|
/* compress dai */
|
2015-10-13 23:41:00 +08:00
|
|
|
int (*compress_new)(struct snd_soc_pcm_runtime *rtd, int num);
|
2017-01-03 23:52:51 +08:00
|
|
|
/* 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
|
|
|
|
|
|
|
/* 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;
|
2011-06-07 23:08:05 +08:00
|
|
|
|
|
|
|
/* probe ordering - for components with runtime dependencies */
|
|
|
|
int probe_order;
|
|
|
|
int remove_order;
|
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
|