Skip to content

Commit

Permalink
Merge series "ASoC: adds new .auto_selectable_formats support" from K…
Browse files Browse the repository at this point in the history
…uninori Morimoto <kuninori.morimoto.gx@renesas.com>:

Hi Mark

These are v3 of "ASoC: adds new .get_fmt support",
but renamed Subject.

This is a little bit challenging patch-set.
The idea/code is almost same as v1 / v2.
v3 has "priority" support.

We need to set dai_link->dai_fmt to select CPU/Codec settings,
and it is selected by Sound Card Driver, today.

Because of it, Sound Card user need to know both CPU / Codec
available dai_fmt, and needs to select it.
For example simple-card / audio-graph case, it is selected by
"format" and "bitclock/frame-master/inversion" on DT.

But, it can be automatically selected if both CPU and Codec drivers
indicate it to ALSA SoC Framework, somehow.

By this patch, dai_fmt can be automatically selected from each
driver if both CPU / Codec driver had .auto_selectable_formats.
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.

It uses Sound Card specified fields preferentially, and try to select
non-specific fields from CPU and Codec driver settings if driver had
.auto_selectable_formats.
In other words, we can select all dai_fmt via Sound Card driver
same as before.

Select dai_fmt 100% automatically is very difficult and will be very complex,
but select automatically some fields only is very easy, I guess.
This patch-set is based on such assumption.

v1 -> v2
	- Add more detail explanation on git-log, code, comment.
	- Possible to be Clock/Frame provider is depends on driver's situation.

v2 -> v3
	- has priority
	- tidyup function explanation for snd_soc_dai_get_fmt()
	- Each driver don't try to have SND_SOC_DAIFMT_CBx_CFx to avoid confusion

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

Kuninori Morimoto (7):
  ASoC: soc-core: move snd_soc_runtime_set_dai_fmt() to upside
  ASoC: soc-core: add snd_soc_runtime_get_dai_fmt()
  ASoC: ak4613: add .auto_selectable_formats support
  ASoC: pcm3168a: add .auto_selectable_formats support
  ASoC: rsnd: add .auto_selectable_formats support
  ASoC: fsi: add .auto_selectable_formats support
  ASoC: hdmi-codec: add .auto_selectable_formats support

 include/sound/soc-dai.h       |  55 +++++++
 sound/soc/codecs/ak4613.c     |  11 ++
 sound/soc/codecs/hdmi-codec.c |  21 +++
 sound/soc/codecs/pcm3168a.c   |  26 +++
 sound/soc/sh/fsi.c            |  15 ++
 sound/soc/sh/rcar/core.c      |  31 +++-
 sound/soc/soc-core.c          | 288 ++++++++++++++++++++++++++--------
 sound/soc/soc-dai.c           |  63 ++++++++
 sound/soc/soc-utils.c         |  29 ++++
 9 files changed, 475 insertions(+), 64 deletions(-)

--
2.25.1
  • Loading branch information
Mark Brown committed Jun 7, 2021
2 parents d50b86b + 68d8b7b commit d08c5b7
Show file tree
Hide file tree
Showing 9 changed files with 475 additions and 64 deletions.
55 changes: 55 additions & 0 deletions include/sound/soc-dai.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J

/* 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)

/*
* DAI Clock gating.
*
Expand All @@ -45,6 +61,17 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */
#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */

/* 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)

/*
* DAI hardware signal polarity.
*
Expand All @@ -71,6 +98,14 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */

/* 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)

/*
* DAI hardware clock providers/consumers
*
Expand All @@ -89,6 +124,14 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC

/* 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)

#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
Expand Down Expand Up @@ -131,6 +174,8 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);

/* Digital Audio interface formatting */
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);
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,
Expand Down Expand Up @@ -292,6 +337,16 @@ struct snd_soc_dai_ops {
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
struct snd_soc_dai *);

/*
* 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;

/* bit field */
unsigned int no_capture_mute:1;
};
Expand Down
11 changes: 11 additions & 0 deletions sound/soc/codecs/ak4613.c
Original file line number Diff line number Diff line change
Expand Up @@ -539,13 +539,24 @@ static int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd,
return 0;
}

/*
* Select below from Sound Card, not Auto
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
static u64 ak4613_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J;

static const struct snd_soc_dai_ops ak4613_dai_ops = {
.startup = ak4613_dai_startup,
.shutdown = ak4613_dai_shutdown,
.set_sysclk = ak4613_dai_set_sysclk,
.set_fmt = ak4613_dai_set_fmt,
.trigger = ak4613_dai_trigger,
.hw_params = ak4613_dai_hw_params,
.auto_selectable_formats = &ak4613_dai_formats,
.num_auto_selectable_formats = 1,
};

#define AK4613_PCM_RATE (SNDRV_PCM_RATE_32000 |\
Expand Down
21 changes: 21 additions & 0 deletions sound/soc/codecs/hdmi-codec.c
Original file line number Diff line number Diff line change
Expand Up @@ -580,12 +580,33 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction)
return -ENOTSUPP;
}

/*
* This driver can select all SND_SOC_DAIFMT_CBx_CFx,
* but need to be selected from Sound Card, not be auto selected.
* Because it might be used from other driver.
* For example,
* ${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c
*/
static u64 hdmi_codec_formats =
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
SND_SOC_POSSIBLE_DAIFMT_NB_IF |
SND_SOC_POSSIBLE_DAIFMT_IB_NF |
SND_SOC_POSSIBLE_DAIFMT_IB_IF |
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B |
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_AC97;

static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = {
.startup = hdmi_codec_startup,
.shutdown = hdmi_codec_shutdown,
.hw_params = hdmi_codec_hw_params,
.set_fmt = hdmi_codec_i2s_set_fmt,
.mute_stream = hdmi_codec_mute,
.auto_selectable_formats = &hdmi_codec_formats,
.num_auto_selectable_formats = 1,
};

static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = {
Expand Down
26 changes: 26 additions & 0 deletions sound/soc/codecs/pcm3168a.c
Original file line number Diff line number Diff line change
Expand Up @@ -573,13 +573,39 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream,
return 0;
}

static u64 pcm3168a_dai_formats[] = {
/*
* Select below from Sound Card, not here
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/

/*
* First Priority
*/
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J,
/*
* Second Priority
*
* These have picky limitation.
* see
* pcm3168a_hw_params()
*/
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};

static const struct snd_soc_dai_ops pcm3168a_dai_ops = {
.set_fmt = pcm3168a_set_dai_fmt,
.set_sysclk = pcm3168a_set_dai_sysclk,
.hw_params = pcm3168a_hw_params,
.mute_stream = pcm3168a_mute,
.set_tdm_slot = pcm3168a_set_tdm_slot,
.no_capture_mute = 1,
.auto_selectable_formats = pcm3168a_dai_formats,
.num_auto_selectable_formats = ARRAY_SIZE(pcm3168a_dai_formats),
};

static struct snd_soc_dai_driver pcm3168a_dais[] = {
Expand Down
15 changes: 15 additions & 0 deletions sound/soc/sh/fsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -1694,12 +1694,27 @@ static int fsi_dai_hw_params(struct snd_pcm_substream *substream,
return 0;
}

/*
* Select below from Sound Card, not auto
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
static u64 fsi_dai_formats =
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
SND_SOC_POSSIBLE_DAIFMT_NB_IF |
SND_SOC_POSSIBLE_DAIFMT_IB_NF |
SND_SOC_POSSIBLE_DAIFMT_IB_IF;

static const struct snd_soc_dai_ops fsi_dai_ops = {
.startup = fsi_dai_startup,
.shutdown = fsi_dai_shutdown,
.trigger = fsi_dai_trigger,
.set_fmt = fsi_dai_set_fmt,
.hw_params = fsi_dai_hw_params,
.auto_selectable_formats = &fsi_dai_formats,
.num_auto_selectable_formats = 1,
};

/*
Expand Down
31 changes: 29 additions & 2 deletions sound/soc/sh/rcar/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -756,10 +756,10 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)

/* set clock master for audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
case SND_SOC_DAIFMT_CBP_CFP:
rdai->clk_master = 0;
break;
case SND_SOC_DAIFMT_CBS_CFS:
case SND_SOC_DAIFMT_CBC_CFC:
rdai->clk_master = 1; /* cpu is master */
break;
default:
Expand Down Expand Up @@ -1039,13 +1039,40 @@ static int rsnd_soc_dai_prepare(struct snd_pcm_substream *substream,
return rsnd_dai_call(prepare, io, priv);
}

static u64 rsnd_soc_dai_formats[] = {
/*
* 1st Priority
*
* Well tested formats.
* Select below from Sound Card, not auto
* SND_SOC_DAIFMT_CBC_CFC
* SND_SOC_DAIFMT_CBP_CFP
*/
SND_SOC_POSSIBLE_DAIFMT_I2S |
SND_SOC_POSSIBLE_DAIFMT_RIGHT_J |
SND_SOC_POSSIBLE_DAIFMT_LEFT_J |
SND_SOC_POSSIBLE_DAIFMT_NB_NF |
SND_SOC_POSSIBLE_DAIFMT_NB_IF |
SND_SOC_POSSIBLE_DAIFMT_IB_NF |
SND_SOC_POSSIBLE_DAIFMT_IB_IF,
/*
* 2nd Priority
*
* Supported, but not well tested
*/
SND_SOC_POSSIBLE_DAIFMT_DSP_A |
SND_SOC_POSSIBLE_DAIFMT_DSP_B,
};

static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
.startup = rsnd_soc_dai_startup,
.shutdown = rsnd_soc_dai_shutdown,
.trigger = rsnd_soc_dai_trigger,
.set_fmt = rsnd_soc_dai_set_fmt,
.set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
.prepare = rsnd_soc_dai_prepare,
.auto_selectable_formats = rsnd_soc_dai_formats,
.num_auto_selectable_formats = ARRAY_SIZE(rsnd_soc_dai_formats),
};

static void rsnd_parse_tdm_split_mode(struct rsnd_priv *priv,
Expand Down
Loading

0 comments on commit d08c5b7

Please sign in to comment.