xref: /openbmc/linux/sound/soc/soc-dai.c (revision b97d6790d03b763eca08847a9a5869a4291b9f9a)
106f6e1d4SKuninori Morimoto // SPDX-License-Identifier: GPL-2.0
206f6e1d4SKuninori Morimoto //
306f6e1d4SKuninori Morimoto // soc-dai.c
406f6e1d4SKuninori Morimoto //
506f6e1d4SKuninori Morimoto // Copyright (C) 2019 Renesas Electronics Corp.
606f6e1d4SKuninori Morimoto // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
706f6e1d4SKuninori Morimoto //
806f6e1d4SKuninori Morimoto 
906f6e1d4SKuninori Morimoto #include <sound/soc.h>
1006f6e1d4SKuninori Morimoto #include <sound/soc-dai.h>
110cbbf8a0SKuninori Morimoto #include <sound/soc-link.h>
1206f6e1d4SKuninori Morimoto 
13aa7b8230SKuninori Morimoto #define soc_dai_ret(dai, ret) _soc_dai_ret(dai, __func__, ret)
_soc_dai_ret(struct snd_soc_dai * dai,const char * func,int ret)14aa7b8230SKuninori Morimoto static inline int _soc_dai_ret(struct snd_soc_dai *dai,
15aa7b8230SKuninori Morimoto 			       const char *func, int ret)
16aa7b8230SKuninori Morimoto {
1728ff437aSPierre-Louis Bossart 	/* Positive, Zero values are not errors */
1828ff437aSPierre-Louis Bossart 	if (ret >= 0)
1928ff437aSPierre-Louis Bossart 		return ret;
2028ff437aSPierre-Louis Bossart 
2128ff437aSPierre-Louis Bossart 	/* Negative values might be errors */
22aa7b8230SKuninori Morimoto 	switch (ret) {
23aa7b8230SKuninori Morimoto 	case -EPROBE_DEFER:
24aa7b8230SKuninori Morimoto 	case -ENOTSUPP:
25aa7b8230SKuninori Morimoto 		break;
26aa7b8230SKuninori Morimoto 	default:
27aa7b8230SKuninori Morimoto 		dev_err(dai->dev,
28aa7b8230SKuninori Morimoto 			"ASoC: error at %s on %s: %d\n",
29aa7b8230SKuninori Morimoto 			func, dai->name, ret);
30aa7b8230SKuninori Morimoto 	}
31aa7b8230SKuninori Morimoto 
32aa7b8230SKuninori Morimoto 	return ret;
33aa7b8230SKuninori Morimoto }
34aa7b8230SKuninori Morimoto 
3500a0b46cSKuninori Morimoto /*
3600a0b46cSKuninori Morimoto  * We might want to check substream by using list.
3700a0b46cSKuninori Morimoto  * In such case, we can update these macros.
3800a0b46cSKuninori Morimoto  */
3900a0b46cSKuninori Morimoto #define soc_dai_mark_push(dai, substream, tgt)	((dai)->mark_##tgt = substream)
4000a0b46cSKuninori Morimoto #define soc_dai_mark_pop(dai, substream, tgt)	((dai)->mark_##tgt = NULL)
4100a0b46cSKuninori Morimoto #define soc_dai_mark_match(dai, substream, tgt)	((dai)->mark_##tgt == substream)
4200a0b46cSKuninori Morimoto 
4306f6e1d4SKuninori Morimoto /**
4406f6e1d4SKuninori Morimoto  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
4506f6e1d4SKuninori Morimoto  * @dai: DAI
4606f6e1d4SKuninori Morimoto  * @clk_id: DAI specific clock ID
4706f6e1d4SKuninori Morimoto  * @freq: new clock frequency in Hz
4806f6e1d4SKuninori Morimoto  * @dir: new clock direction - input/output.
4906f6e1d4SKuninori Morimoto  *
5006f6e1d4SKuninori Morimoto  * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
5106f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_sysclk(struct snd_soc_dai * dai,int clk_id,unsigned int freq,int dir)5206f6e1d4SKuninori Morimoto int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
5306f6e1d4SKuninori Morimoto 			   unsigned int freq, int dir)
5406f6e1d4SKuninori Morimoto {
55aa7b8230SKuninori Morimoto 	int ret;
5606f6e1d4SKuninori Morimoto 
57479914edSKuninori Morimoto 	if (dai->driver->ops &&
58479914edSKuninori Morimoto 	    dai->driver->ops->set_sysclk)
59aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
60aa7b8230SKuninori Morimoto 	else
61aa7b8230SKuninori Morimoto 		ret = snd_soc_component_set_sysclk(dai->component, clk_id, 0,
6206f6e1d4SKuninori Morimoto 						   freq, dir);
63aa7b8230SKuninori Morimoto 
64aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
6506f6e1d4SKuninori Morimoto }
6606f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
6706f6e1d4SKuninori Morimoto 
6806f6e1d4SKuninori Morimoto /**
6906f6e1d4SKuninori Morimoto  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
7006f6e1d4SKuninori Morimoto  * @dai: DAI
7106f6e1d4SKuninori Morimoto  * @div_id: DAI specific clock divider ID
7206f6e1d4SKuninori Morimoto  * @div: new clock divisor.
7306f6e1d4SKuninori Morimoto  *
7406f6e1d4SKuninori Morimoto  * Configures the clock dividers. This is used to derive the best DAI bit and
7506f6e1d4SKuninori Morimoto  * frame clocks from the system or master clock. It's best to set the DAI bit
7606f6e1d4SKuninori Morimoto  * and frame clocks as low as possible to save system power.
7706f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_clkdiv(struct snd_soc_dai * dai,int div_id,int div)7806f6e1d4SKuninori Morimoto int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
7906f6e1d4SKuninori Morimoto 			   int div_id, int div)
8006f6e1d4SKuninori Morimoto {
81aa7b8230SKuninori Morimoto 	int ret = -EINVAL;
82aa7b8230SKuninori Morimoto 
83479914edSKuninori Morimoto 	if (dai->driver->ops &&
84479914edSKuninori Morimoto 	    dai->driver->ops->set_clkdiv)
85aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_clkdiv(dai, div_id, div);
86aa7b8230SKuninori Morimoto 
87aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
8806f6e1d4SKuninori Morimoto }
8906f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
9006f6e1d4SKuninori Morimoto 
9106f6e1d4SKuninori Morimoto /**
9206f6e1d4SKuninori Morimoto  * snd_soc_dai_set_pll - configure DAI PLL.
9306f6e1d4SKuninori Morimoto  * @dai: DAI
9406f6e1d4SKuninori Morimoto  * @pll_id: DAI specific PLL ID
9506f6e1d4SKuninori Morimoto  * @source: DAI specific source for the PLL
9606f6e1d4SKuninori Morimoto  * @freq_in: PLL input clock frequency in Hz
9706f6e1d4SKuninori Morimoto  * @freq_out: requested PLL output clock frequency in Hz
9806f6e1d4SKuninori Morimoto  *
9906f6e1d4SKuninori Morimoto  * Configures and enables PLL to generate output clock based on input clock.
10006f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_pll(struct snd_soc_dai * dai,int pll_id,int source,unsigned int freq_in,unsigned int freq_out)10106f6e1d4SKuninori Morimoto int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
10206f6e1d4SKuninori Morimoto 			unsigned int freq_in, unsigned int freq_out)
10306f6e1d4SKuninori Morimoto {
104aa7b8230SKuninori Morimoto 	int ret;
105aa7b8230SKuninori Morimoto 
106479914edSKuninori Morimoto 	if (dai->driver->ops &&
107479914edSKuninori Morimoto 	    dai->driver->ops->set_pll)
108aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_pll(dai, pll_id, source,
109aa7b8230SKuninori Morimoto 						freq_in, freq_out);
110aa7b8230SKuninori Morimoto 	else
111aa7b8230SKuninori Morimoto 		ret = snd_soc_component_set_pll(dai->component, pll_id, source,
11206f6e1d4SKuninori Morimoto 						freq_in, freq_out);
11306f6e1d4SKuninori Morimoto 
114aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
11506f6e1d4SKuninori Morimoto }
11606f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
11706f6e1d4SKuninori Morimoto 
11806f6e1d4SKuninori Morimoto /**
11906f6e1d4SKuninori Morimoto  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
12006f6e1d4SKuninori Morimoto  * @dai: DAI
12106f6e1d4SKuninori Morimoto  * @ratio: Ratio of BCLK to Sample rate.
12206f6e1d4SKuninori Morimoto  *
12306f6e1d4SKuninori Morimoto  * Configures the DAI for a preset BCLK to sample rate ratio.
12406f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_bclk_ratio(struct snd_soc_dai * dai,unsigned int ratio)12506f6e1d4SKuninori Morimoto int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
12606f6e1d4SKuninori Morimoto {
127ceff365aSMartin Povišer 	int ret = -ENOTSUPP;
128aa7b8230SKuninori Morimoto 
129479914edSKuninori Morimoto 	if (dai->driver->ops &&
130479914edSKuninori Morimoto 	    dai->driver->ops->set_bclk_ratio)
131aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_bclk_ratio(dai, ratio);
132aa7b8230SKuninori Morimoto 
133aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
13406f6e1d4SKuninori Morimoto }
13506f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
13606f6e1d4SKuninori Morimoto 
snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime * rtd)137ba9e82a1SKuninori Morimoto int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd)
138ba9e82a1SKuninori Morimoto {
139ba9e82a1SKuninori Morimoto 	struct snd_soc_dai *dai;
140ba9e82a1SKuninori Morimoto 	int i, max = 0;
141ba9e82a1SKuninori Morimoto 
142ba9e82a1SKuninori Morimoto 	/*
143ba9e82a1SKuninori Morimoto 	 * return max num if *ALL* DAIs have .auto_selectable_formats
144ba9e82a1SKuninori Morimoto 	 */
145ba9e82a1SKuninori Morimoto 	for_each_rtd_dais(rtd, i, dai) {
146ba9e82a1SKuninori Morimoto 		if (dai->driver->ops &&
147ba9e82a1SKuninori Morimoto 		    dai->driver->ops->num_auto_selectable_formats)
148ba9e82a1SKuninori Morimoto 			max = max(max, dai->driver->ops->num_auto_selectable_formats);
149ba9e82a1SKuninori Morimoto 		else
150ba9e82a1SKuninori Morimoto 			return 0;
151ba9e82a1SKuninori Morimoto 	}
152ba9e82a1SKuninori Morimoto 
153ba9e82a1SKuninori Morimoto 	return max;
154ba9e82a1SKuninori Morimoto }
155ba9e82a1SKuninori Morimoto 
156ba9e82a1SKuninori Morimoto /**
157ba9e82a1SKuninori Morimoto  * snd_soc_dai_get_fmt - get supported audio format.
158ba9e82a1SKuninori Morimoto  * @dai: DAI
159ba9e82a1SKuninori Morimoto  * @priority: priority level of supported audio format.
160ba9e82a1SKuninori Morimoto  *
161ba9e82a1SKuninori Morimoto  * This should return only formats implemented with high
162ba9e82a1SKuninori Morimoto  * quality by the DAI so that the core can configure a
163ba9e82a1SKuninori Morimoto  * format which will work well with other devices.
164ba9e82a1SKuninori Morimoto  * For example devices which don't support both edges of the
165ba9e82a1SKuninori Morimoto  * LRCLK signal in I2S style formats should only list DSP
166ba9e82a1SKuninori Morimoto  * modes.  This will mean that sometimes fewer formats
167ba9e82a1SKuninori Morimoto  * are reported here than are supported by set_fmt().
168ba9e82a1SKuninori Morimoto  */
snd_soc_dai_get_fmt(struct snd_soc_dai * dai,int priority)169ba9e82a1SKuninori Morimoto u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority)
170ba9e82a1SKuninori Morimoto {
171ba9e82a1SKuninori Morimoto 	const struct snd_soc_dai_ops *ops = dai->driver->ops;
172ba9e82a1SKuninori Morimoto 	u64 fmt = 0;
173ba9e82a1SKuninori Morimoto 	int i, max = 0, until = priority;
174ba9e82a1SKuninori Morimoto 
175ba9e82a1SKuninori Morimoto 	/*
176ba9e82a1SKuninori Morimoto 	 * Collect auto_selectable_formats until priority
177ba9e82a1SKuninori Morimoto 	 *
178ba9e82a1SKuninori Morimoto 	 * ex)
179ba9e82a1SKuninori Morimoto 	 *	auto_selectable_formats[] = { A, B, C };
180ba9e82a1SKuninori Morimoto 	 *	(A, B, C = SND_SOC_POSSIBLE_DAIFMT_xxx)
181ba9e82a1SKuninori Morimoto 	 *
182ba9e82a1SKuninori Morimoto 	 * priority = 1 :	A
183ba9e82a1SKuninori Morimoto 	 * priority = 2 :	A | B
184ba9e82a1SKuninori Morimoto 	 * priority = 3 :	A | B | C
185ba9e82a1SKuninori Morimoto 	 * priority = 4 :	A | B | C
186ba9e82a1SKuninori Morimoto 	 * ...
187ba9e82a1SKuninori Morimoto 	 */
188ba9e82a1SKuninori Morimoto 	if (ops)
189ba9e82a1SKuninori Morimoto 		max = ops->num_auto_selectable_formats;
190ba9e82a1SKuninori Morimoto 
191ba9e82a1SKuninori Morimoto 	if (max < until)
192ba9e82a1SKuninori Morimoto 		until = max;
193ba9e82a1SKuninori Morimoto 
194ba9e82a1SKuninori Morimoto 	for (i = 0; i < until; i++)
195ba9e82a1SKuninori Morimoto 		fmt |= ops->auto_selectable_formats[i];
196ba9e82a1SKuninori Morimoto 
197ba9e82a1SKuninori Morimoto 	return fmt;
198ba9e82a1SKuninori Morimoto }
199ba9e82a1SKuninori Morimoto 
20006f6e1d4SKuninori Morimoto /**
20106f6e1d4SKuninori Morimoto  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
20206f6e1d4SKuninori Morimoto  * @dai: DAI
20306f6e1d4SKuninori Morimoto  * @fmt: SND_SOC_DAIFMT_* format value.
20406f6e1d4SKuninori Morimoto  *
20506f6e1d4SKuninori Morimoto  * Configures the DAI hardware format and clocking.
20606f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_fmt(struct snd_soc_dai * dai,unsigned int fmt)20706f6e1d4SKuninori Morimoto int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
20806f6e1d4SKuninori Morimoto {
209aa7b8230SKuninori Morimoto 	int ret = -ENOTSUPP;
210aa7b8230SKuninori Morimoto 
21119423951SCharles Keepax 	if (dai->driver->ops && dai->driver->ops->set_fmt)
212aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_fmt(dai, fmt);
213aa7b8230SKuninori Morimoto 
214aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
21506f6e1d4SKuninori Morimoto }
21606f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
21706f6e1d4SKuninori Morimoto 
21806f6e1d4SKuninori Morimoto /**
2192fb87110SPierre-Louis Bossart  * snd_soc_xlate_tdm_slot_mask - generate tx/rx slot mask.
22006f6e1d4SKuninori Morimoto  * @slots: Number of slots in use.
22106f6e1d4SKuninori Morimoto  * @tx_mask: bitmask representing active TX slots.
22206f6e1d4SKuninori Morimoto  * @rx_mask: bitmask representing active RX slots.
22306f6e1d4SKuninori Morimoto  *
22406f6e1d4SKuninori Morimoto  * Generates the TDM tx and rx slot default masks for DAI.
22506f6e1d4SKuninori Morimoto  */
snd_soc_xlate_tdm_slot_mask(unsigned int slots,unsigned int * tx_mask,unsigned int * rx_mask)22606f6e1d4SKuninori Morimoto static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
22706f6e1d4SKuninori Morimoto 				       unsigned int *tx_mask,
22806f6e1d4SKuninori Morimoto 				       unsigned int *rx_mask)
22906f6e1d4SKuninori Morimoto {
23006f6e1d4SKuninori Morimoto 	if (*tx_mask || *rx_mask)
23106f6e1d4SKuninori Morimoto 		return 0;
23206f6e1d4SKuninori Morimoto 
23306f6e1d4SKuninori Morimoto 	if (!slots)
23406f6e1d4SKuninori Morimoto 		return -EINVAL;
23506f6e1d4SKuninori Morimoto 
23606f6e1d4SKuninori Morimoto 	*tx_mask = (1 << slots) - 1;
23706f6e1d4SKuninori Morimoto 	*rx_mask = (1 << slots) - 1;
23806f6e1d4SKuninori Morimoto 
23906f6e1d4SKuninori Morimoto 	return 0;
24006f6e1d4SKuninori Morimoto }
24106f6e1d4SKuninori Morimoto 
24206f6e1d4SKuninori Morimoto /**
24306f6e1d4SKuninori Morimoto  * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
24406f6e1d4SKuninori Morimoto  * @dai: The DAI to configure
24506f6e1d4SKuninori Morimoto  * @tx_mask: bitmask representing active TX slots.
24606f6e1d4SKuninori Morimoto  * @rx_mask: bitmask representing active RX slots.
24706f6e1d4SKuninori Morimoto  * @slots: Number of slots in use.
24806f6e1d4SKuninori Morimoto  * @slot_width: Width in bits for each slot.
24906f6e1d4SKuninori Morimoto  *
25006f6e1d4SKuninori Morimoto  * This function configures the specified DAI for TDM operation. @slot contains
25106f6e1d4SKuninori Morimoto  * the total number of slots of the TDM stream and @slot_with the width of each
25206f6e1d4SKuninori Morimoto  * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
25306f6e1d4SKuninori Morimoto  * active slots of the TDM stream for the specified DAI, i.e. which slots the
25406f6e1d4SKuninori Morimoto  * DAI should write to or read from. If a bit is set the corresponding slot is
25506f6e1d4SKuninori Morimoto  * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
25606f6e1d4SKuninori Morimoto  * the first slot, bit 1 to the second slot and so on. The first active slot
25706f6e1d4SKuninori Morimoto  * maps to the first channel of the DAI, the second active slot to the second
25806f6e1d4SKuninori Morimoto  * channel and so on.
25906f6e1d4SKuninori Morimoto  *
26006f6e1d4SKuninori Morimoto  * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
26106f6e1d4SKuninori Morimoto  * @rx_mask and @slot_width will be ignored.
26206f6e1d4SKuninori Morimoto  *
26306f6e1d4SKuninori Morimoto  * Returns 0 on success, a negative error code otherwise.
26406f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_tdm_slot(struct snd_soc_dai * dai,unsigned int tx_mask,unsigned int rx_mask,int slots,int slot_width)26506f6e1d4SKuninori Morimoto int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
26606f6e1d4SKuninori Morimoto 			     unsigned int tx_mask, unsigned int rx_mask,
26706f6e1d4SKuninori Morimoto 			     int slots, int slot_width)
26806f6e1d4SKuninori Morimoto {
269aa7b8230SKuninori Morimoto 	int ret = -ENOTSUPP;
2708ede4b71SKuninori Morimoto 	int stream;
2718ede4b71SKuninori Morimoto 	unsigned int *tdm_mask[] = {
2728ede4b71SKuninori Morimoto 		&tx_mask,
2738ede4b71SKuninori Morimoto 		&rx_mask,
2748ede4b71SKuninori Morimoto 	};
275aa7b8230SKuninori Morimoto 
276479914edSKuninori Morimoto 	if (dai->driver->ops &&
277479914edSKuninori Morimoto 	    dai->driver->ops->xlate_tdm_slot_mask)
27806f6e1d4SKuninori Morimoto 		dai->driver->ops->xlate_tdm_slot_mask(slots,
27906f6e1d4SKuninori Morimoto 						      &tx_mask, &rx_mask);
28006f6e1d4SKuninori Morimoto 	else
28106f6e1d4SKuninori Morimoto 		snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
28206f6e1d4SKuninori Morimoto 
2838ede4b71SKuninori Morimoto 	for_each_pcm_streams(stream)
2848ede4b71SKuninori Morimoto 		snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]);
28506f6e1d4SKuninori Morimoto 
286479914edSKuninori Morimoto 	if (dai->driver->ops &&
287479914edSKuninori Morimoto 	    dai->driver->ops->set_tdm_slot)
288aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
28906f6e1d4SKuninori Morimoto 						      slots, slot_width);
290aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
29106f6e1d4SKuninori Morimoto }
29206f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
29306f6e1d4SKuninori Morimoto 
29406f6e1d4SKuninori Morimoto /**
29506f6e1d4SKuninori Morimoto  * snd_soc_dai_set_channel_map - configure DAI audio channel map
29606f6e1d4SKuninori Morimoto  * @dai: DAI
29706f6e1d4SKuninori Morimoto  * @tx_num: how many TX channels
29806f6e1d4SKuninori Morimoto  * @tx_slot: pointer to an array which imply the TX slot number channel
29906f6e1d4SKuninori Morimoto  *           0~num-1 uses
30006f6e1d4SKuninori Morimoto  * @rx_num: how many RX channels
30106f6e1d4SKuninori Morimoto  * @rx_slot: pointer to an array which imply the RX slot number channel
30206f6e1d4SKuninori Morimoto  *           0~num-1 uses
30306f6e1d4SKuninori Morimoto  *
30406f6e1d4SKuninori Morimoto  * configure the relationship between channel number and TDM slot number.
30506f6e1d4SKuninori Morimoto  */
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)30606f6e1d4SKuninori Morimoto int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
30706f6e1d4SKuninori Morimoto 				unsigned int tx_num, unsigned int *tx_slot,
30806f6e1d4SKuninori Morimoto 				unsigned int rx_num, unsigned int *rx_slot)
30906f6e1d4SKuninori Morimoto {
310aa7b8230SKuninori Morimoto 	int ret = -ENOTSUPP;
311aa7b8230SKuninori Morimoto 
312479914edSKuninori Morimoto 	if (dai->driver->ops &&
313479914edSKuninori Morimoto 	    dai->driver->ops->set_channel_map)
314aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
31506f6e1d4SKuninori Morimoto 							rx_num, rx_slot);
316aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
31706f6e1d4SKuninori Morimoto }
31806f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
31906f6e1d4SKuninori Morimoto 
32006f6e1d4SKuninori Morimoto /**
32106f6e1d4SKuninori Morimoto  * snd_soc_dai_get_channel_map - Get DAI audio channel map
32206f6e1d4SKuninori Morimoto  * @dai: DAI
32306f6e1d4SKuninori Morimoto  * @tx_num: how many TX channels
32406f6e1d4SKuninori Morimoto  * @tx_slot: pointer to an array which imply the TX slot number channel
32506f6e1d4SKuninori Morimoto  *           0~num-1 uses
32606f6e1d4SKuninori Morimoto  * @rx_num: how many RX channels
32706f6e1d4SKuninori Morimoto  * @rx_slot: pointer to an array which imply the RX slot number channel
32806f6e1d4SKuninori Morimoto  *           0~num-1 uses
32906f6e1d4SKuninori Morimoto  */
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)33006f6e1d4SKuninori Morimoto int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
33106f6e1d4SKuninori Morimoto 				unsigned int *tx_num, unsigned int *tx_slot,
33206f6e1d4SKuninori Morimoto 				unsigned int *rx_num, unsigned int *rx_slot)
33306f6e1d4SKuninori Morimoto {
334aa7b8230SKuninori Morimoto 	int ret = -ENOTSUPP;
335aa7b8230SKuninori Morimoto 
336479914edSKuninori Morimoto 	if (dai->driver->ops &&
337479914edSKuninori Morimoto 	    dai->driver->ops->get_channel_map)
338aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
33906f6e1d4SKuninori Morimoto 							rx_num, rx_slot);
340aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
34106f6e1d4SKuninori Morimoto }
34206f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
34306f6e1d4SKuninori Morimoto 
34406f6e1d4SKuninori Morimoto /**
34506f6e1d4SKuninori Morimoto  * snd_soc_dai_set_tristate - configure DAI system or master clock.
34606f6e1d4SKuninori Morimoto  * @dai: DAI
34706f6e1d4SKuninori Morimoto  * @tristate: tristate enable
34806f6e1d4SKuninori Morimoto  *
34906f6e1d4SKuninori Morimoto  * Tristates the DAI so that others can use it.
35006f6e1d4SKuninori Morimoto  */
snd_soc_dai_set_tristate(struct snd_soc_dai * dai,int tristate)35106f6e1d4SKuninori Morimoto int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
35206f6e1d4SKuninori Morimoto {
353aa7b8230SKuninori Morimoto 	int ret = -EINVAL;
354aa7b8230SKuninori Morimoto 
355479914edSKuninori Morimoto 	if (dai->driver->ops &&
356479914edSKuninori Morimoto 	    dai->driver->ops->set_tristate)
357aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->set_tristate(dai, tristate);
358aa7b8230SKuninori Morimoto 
359aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
36006f6e1d4SKuninori Morimoto }
36106f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
36206f6e1d4SKuninori Morimoto 
36306f6e1d4SKuninori Morimoto /**
36406f6e1d4SKuninori Morimoto  * snd_soc_dai_digital_mute - configure DAI system or master clock.
36506f6e1d4SKuninori Morimoto  * @dai: DAI
36606f6e1d4SKuninori Morimoto  * @mute: mute enable
36706f6e1d4SKuninori Morimoto  * @direction: stream to mute
36806f6e1d4SKuninori Morimoto  *
36906f6e1d4SKuninori Morimoto  * Mutes the DAI DAC.
37006f6e1d4SKuninori Morimoto  */
snd_soc_dai_digital_mute(struct snd_soc_dai * dai,int mute,int direction)37106f6e1d4SKuninori Morimoto int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
37206f6e1d4SKuninori Morimoto 			     int direction)
37306f6e1d4SKuninori Morimoto {
374aa7b8230SKuninori Morimoto 	int ret = -ENOTSUPP;
375aa7b8230SKuninori Morimoto 
376350d9935SKuninori Morimoto 	/*
377350d9935SKuninori Morimoto 	 * ignore if direction was CAPTURE
378350d9935SKuninori Morimoto 	 * and it had .no_capture_mute flag
379350d9935SKuninori Morimoto 	 */
380479914edSKuninori Morimoto 	if (dai->driver->ops &&
381350d9935SKuninori Morimoto 	    dai->driver->ops->mute_stream &&
382350d9935SKuninori Morimoto 	    (direction == SNDRV_PCM_STREAM_PLAYBACK ||
383350d9935SKuninori Morimoto 	     !dai->driver->ops->no_capture_mute))
384aa7b8230SKuninori Morimoto 		ret = dai->driver->ops->mute_stream(dai, mute, direction);
385aa7b8230SKuninori Morimoto 
386aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
38706f6e1d4SKuninori Morimoto }
38806f6e1d4SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
389aa6166c2SKuninori Morimoto 
snd_soc_dai_hw_params(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params)390aa6166c2SKuninori Morimoto int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
391aa6166c2SKuninori Morimoto 			  struct snd_pcm_substream *substream,
392aa6166c2SKuninori Morimoto 			  struct snd_pcm_hw_params *params)
393aa6166c2SKuninori Morimoto {
394aa7b8230SKuninori Morimoto 	int ret = 0;
395aa6166c2SKuninori Morimoto 
3968b4ba1d3SGyeongtaek Lee 	if (dai->driver->ops &&
3973115be55SRichard Fitzgerald 	    dai->driver->ops->hw_params)
398aa6166c2SKuninori Morimoto 		ret = dai->driver->ops->hw_params(substream, params, dai);
399c304c9acSKuninori Morimoto 
400c304c9acSKuninori Morimoto 	/* mark substream if succeeded */
401c304c9acSKuninori Morimoto 	if (ret == 0)
402c304c9acSKuninori Morimoto 		soc_dai_mark_push(dai, substream, hw_params);
4033115be55SRichard Fitzgerald 
404aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
405aa6166c2SKuninori Morimoto }
406846faaedSKuninori Morimoto 
snd_soc_dai_hw_free(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int rollback)407846faaedSKuninori Morimoto void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
408c304c9acSKuninori Morimoto 			 struct snd_pcm_substream *substream,
409c304c9acSKuninori Morimoto 			 int rollback)
410846faaedSKuninori Morimoto {
411c304c9acSKuninori Morimoto 	if (rollback && !soc_dai_mark_match(dai, substream, hw_params))
412c304c9acSKuninori Morimoto 		return;
413c304c9acSKuninori Morimoto 
414479914edSKuninori Morimoto 	if (dai->driver->ops &&
415479914edSKuninori Morimoto 	    dai->driver->ops->hw_free)
416846faaedSKuninori Morimoto 		dai->driver->ops->hw_free(substream, dai);
417c304c9acSKuninori Morimoto 
418c304c9acSKuninori Morimoto 	/* remove marked substream */
419c304c9acSKuninori Morimoto 	soc_dai_mark_pop(dai, substream, hw_params);
420846faaedSKuninori Morimoto }
4215a52a045SKuninori Morimoto 
snd_soc_dai_startup(struct snd_soc_dai * dai,struct snd_pcm_substream * substream)4225a52a045SKuninori Morimoto int snd_soc_dai_startup(struct snd_soc_dai *dai,
4235a52a045SKuninori Morimoto 			struct snd_pcm_substream *substream)
4245a52a045SKuninori Morimoto {
4255a52a045SKuninori Morimoto 	int ret = 0;
4265a52a045SKuninori Morimoto 
4274005d1baSPeter Suti 	if (!snd_soc_dai_stream_valid(dai, substream->stream))
4284005d1baSPeter Suti 		return 0;
4294005d1baSPeter Suti 
430479914edSKuninori Morimoto 	if (dai->driver->ops &&
431479914edSKuninori Morimoto 	    dai->driver->ops->startup)
4325a52a045SKuninori Morimoto 		ret = dai->driver->ops->startup(substream, dai);
4335a52a045SKuninori Morimoto 
43400a0b46cSKuninori Morimoto 	/* mark substream if succeeded */
43500a0b46cSKuninori Morimoto 	if (ret == 0)
43600a0b46cSKuninori Morimoto 		soc_dai_mark_push(dai, substream, startup);
43700a0b46cSKuninori Morimoto 
438aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
4395a52a045SKuninori Morimoto }
440330fcb51SKuninori Morimoto 
snd_soc_dai_shutdown(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int rollback)441330fcb51SKuninori Morimoto void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
44200a0b46cSKuninori Morimoto 			  struct snd_pcm_substream *substream,
44300a0b46cSKuninori Morimoto 			  int rollback)
444330fcb51SKuninori Morimoto {
4454005d1baSPeter Suti 	if (!snd_soc_dai_stream_valid(dai, substream->stream))
4464005d1baSPeter Suti 		return;
4474005d1baSPeter Suti 
44800a0b46cSKuninori Morimoto 	if (rollback && !soc_dai_mark_match(dai, substream, startup))
44900a0b46cSKuninori Morimoto 		return;
45000a0b46cSKuninori Morimoto 
451479914edSKuninori Morimoto 	if (dai->driver->ops &&
452479914edSKuninori Morimoto 	    dai->driver->ops->shutdown)
453330fcb51SKuninori Morimoto 		dai->driver->ops->shutdown(substream, dai);
45400a0b46cSKuninori Morimoto 
45500a0b46cSKuninori Morimoto 	/* remove marked substream */
45600a0b46cSKuninori Morimoto 	soc_dai_mark_pop(dai, substream, startup);
457330fcb51SKuninori Morimoto }
4584beb8e10SKuninori Morimoto 
snd_soc_dai_compress_new(struct snd_soc_dai * dai,struct snd_soc_pcm_runtime * rtd,int num)459b423c420SKuninori Morimoto int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
460b423c420SKuninori Morimoto 			     struct snd_soc_pcm_runtime *rtd, int num)
461b423c420SKuninori Morimoto {
462aa7b8230SKuninori Morimoto 	int ret = -ENOTSUPP;
463624fee45SKuninori Morimoto 	if (dai->driver->ops &&
464624fee45SKuninori Morimoto 	    dai->driver->ops->compress_new)
465624fee45SKuninori Morimoto 		ret = dai->driver->ops->compress_new(rtd, num);
466aa7b8230SKuninori Morimoto 	return soc_dai_ret(dai, ret);
467b423c420SKuninori Morimoto }
468467fece8SKuninori Morimoto 
469467fece8SKuninori Morimoto /*
470467fece8SKuninori Morimoto  * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
471467fece8SKuninori Morimoto  *
472467fece8SKuninori Morimoto  * Returns true if the DAI supports the indicated stream type.
473467fece8SKuninori Morimoto  */
snd_soc_dai_stream_valid(struct snd_soc_dai * dai,int dir)474467fece8SKuninori Morimoto bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
475467fece8SKuninori Morimoto {
476acf253c1SKuninori Morimoto 	struct snd_soc_pcm_stream *stream = snd_soc_dai_get_pcm_stream(dai, dir);
477467fece8SKuninori Morimoto 
478467fece8SKuninori Morimoto 	/* If the codec specifies any channels at all, it supports the stream */
479467fece8SKuninori Morimoto 	return stream->channels_min;
480467fece8SKuninori Morimoto }
4810b73ba55SKuninori Morimoto 
48225612477SPierre-Louis Bossart /*
48325612477SPierre-Louis Bossart  * snd_soc_dai_link_set_capabilities() - set dai_link properties based on its DAIs
48425612477SPierre-Louis Bossart  */
snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link * dai_link)48525612477SPierre-Louis Bossart void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link)
48625612477SPierre-Louis Bossart {
487d490f4e7SKuninori Morimoto 	bool supported[SNDRV_PCM_STREAM_LAST + 1];
488d490f4e7SKuninori Morimoto 	int direction;
489d490f4e7SKuninori Morimoto 
490d490f4e7SKuninori Morimoto 	for_each_pcm_streams(direction) {
49125612477SPierre-Louis Bossart 		struct snd_soc_dai_link_component *cpu;
49225612477SPierre-Louis Bossart 		struct snd_soc_dai_link_component *codec;
49325612477SPierre-Louis Bossart 		struct snd_soc_dai *dai;
494d490f4e7SKuninori Morimoto 		bool supported_cpu = false;
495d490f4e7SKuninori Morimoto 		bool supported_codec = false;
49625612477SPierre-Louis Bossart 		int i;
49725612477SPierre-Louis Bossart 
49825612477SPierre-Louis Bossart 		for_each_link_cpus(dai_link, i, cpu) {
499c1c277b2SKuninori Morimoto 			dai = snd_soc_find_dai_with_mutex(cpu);
5004f872154SPierre-Louis Bossart 			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
5014f872154SPierre-Louis Bossart 				supported_cpu = true;
50225612477SPierre-Louis Bossart 				break;
50325612477SPierre-Louis Bossart 			}
50425612477SPierre-Louis Bossart 		}
50525612477SPierre-Louis Bossart 		for_each_link_codecs(dai_link, i, codec) {
506c1c277b2SKuninori Morimoto 			dai = snd_soc_find_dai_with_mutex(codec);
5074f872154SPierre-Louis Bossart 			if (dai && snd_soc_dai_stream_valid(dai, direction)) {
5084f872154SPierre-Louis Bossart 				supported_codec = true;
50925612477SPierre-Louis Bossart 				break;
51025612477SPierre-Louis Bossart 			}
51125612477SPierre-Louis Bossart 		}
5124f872154SPierre-Louis Bossart 		supported[direction] = supported_cpu && supported_codec;
51325612477SPierre-Louis Bossart 	}
51425612477SPierre-Louis Bossart 
51525612477SPierre-Louis Bossart 	dai_link->dpcm_playback = supported[SNDRV_PCM_STREAM_PLAYBACK];
51625612477SPierre-Louis Bossart 	dai_link->dpcm_capture  = supported[SNDRV_PCM_STREAM_CAPTURE];
51725612477SPierre-Louis Bossart }
51825612477SPierre-Louis Bossart EXPORT_SYMBOL_GPL(snd_soc_dai_link_set_capabilities);
51925612477SPierre-Louis Bossart 
snd_soc_dai_action(struct snd_soc_dai * dai,int stream,int action)520dc829106SKuninori Morimoto void snd_soc_dai_action(struct snd_soc_dai *dai,
521dc829106SKuninori Morimoto 			int stream, int action)
522dc829106SKuninori Morimoto {
5235552f8d7SKuninori Morimoto 	/* see snd_soc_dai_stream_active() */
5243653480cSKuninori Morimoto 	dai->stream[stream].active	+= action;
5250812a08aSKuninori Morimoto 
526488b2ca5SKuninori Morimoto 	/* see snd_soc_component_active() */
527dc829106SKuninori Morimoto 	dai->component->active		+= action;
528dc829106SKuninori Morimoto }
529dc829106SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_action);
530dc829106SKuninori Morimoto 
snd_soc_dai_active(struct snd_soc_dai * dai)531efffd9b3SKuninori Morimoto int snd_soc_dai_active(struct snd_soc_dai *dai)
532efffd9b3SKuninori Morimoto {
533efffd9b3SKuninori Morimoto 	int stream, active;
534efffd9b3SKuninori Morimoto 
535efffd9b3SKuninori Morimoto 	active = 0;
536efffd9b3SKuninori Morimoto 	for_each_pcm_streams(stream)
5373653480cSKuninori Morimoto 		active += dai->stream[stream].active;
538efffd9b3SKuninori Morimoto 
539efffd9b3SKuninori Morimoto 	return active;
540efffd9b3SKuninori Morimoto }
541efffd9b3SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_active);
542efffd9b3SKuninori Morimoto 
snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime * rtd,int order)54351801aeaSKuninori Morimoto int snd_soc_pcm_dai_probe(struct snd_soc_pcm_runtime *rtd, int order)
54451801aeaSKuninori Morimoto {
54551801aeaSKuninori Morimoto 	struct snd_soc_dai *dai;
54651801aeaSKuninori Morimoto 	int i;
54751801aeaSKuninori Morimoto 
54851801aeaSKuninori Morimoto 	for_each_rtd_dais(rtd, i, dai) {
5495c5a7521SKuninori Morimoto 		if (dai->probed)
5505c5a7521SKuninori Morimoto 			continue;
5515c5a7521SKuninori Morimoto 
552624fee45SKuninori Morimoto 		if (dai->driver->ops) {
553624fee45SKuninori Morimoto 			if (dai->driver->ops->probe_order != order)
554624fee45SKuninori Morimoto 				continue;
555624fee45SKuninori Morimoto 
556624fee45SKuninori Morimoto 			if (dai->driver->ops->probe) {
557624fee45SKuninori Morimoto 				int ret = dai->driver->ops->probe(dai);
55851801aeaSKuninori Morimoto 
55951801aeaSKuninori Morimoto 				if (ret < 0)
56051801aeaSKuninori Morimoto 					return soc_dai_ret(dai, ret);
56151801aeaSKuninori Morimoto 			}
562624fee45SKuninori Morimoto 		}
56351801aeaSKuninori Morimoto 		dai->probed = 1;
56451801aeaSKuninori Morimoto 	}
56551801aeaSKuninori Morimoto 
56651801aeaSKuninori Morimoto 	return 0;
56751801aeaSKuninori Morimoto }
56851801aeaSKuninori Morimoto 
snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime * rtd,int order)5697eaa313bSKuninori Morimoto int snd_soc_pcm_dai_remove(struct snd_soc_pcm_runtime *rtd, int order)
5707eaa313bSKuninori Morimoto {
5717eaa313bSKuninori Morimoto 	struct snd_soc_dai *dai;
5727eaa313bSKuninori Morimoto 	int i, r, ret = 0;
5737eaa313bSKuninori Morimoto 
5747eaa313bSKuninori Morimoto 	for_each_rtd_dais(rtd, i, dai) {
575624fee45SKuninori Morimoto 		if (!dai->probed)
5767eaa313bSKuninori Morimoto 			continue;
5777eaa313bSKuninori Morimoto 
578624fee45SKuninori Morimoto 		if (dai->driver->ops) {
579624fee45SKuninori Morimoto 			if (dai->driver->ops->remove_order != order)
580624fee45SKuninori Morimoto 				continue;
581624fee45SKuninori Morimoto 
582624fee45SKuninori Morimoto 			if (dai->driver->ops->remove) {
583624fee45SKuninori Morimoto 				r = dai->driver->ops->remove(dai);
5847eaa313bSKuninori Morimoto 				if (r < 0)
5857eaa313bSKuninori Morimoto 					ret = r; /* use last error */
5867eaa313bSKuninori Morimoto 			}
587624fee45SKuninori Morimoto 		}
5887eaa313bSKuninori Morimoto 		dai->probed = 0;
5897eaa313bSKuninori Morimoto 	}
5907eaa313bSKuninori Morimoto 
5917eaa313bSKuninori Morimoto 	return ret;
5927eaa313bSKuninori Morimoto }
5937eaa313bSKuninori Morimoto 
snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime * rtd)5940b73ba55SKuninori Morimoto int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd)
5950b73ba55SKuninori Morimoto {
5960b73ba55SKuninori Morimoto 	struct snd_soc_dai *dai;
597454a7422SKuninori Morimoto 	int i;
5980b73ba55SKuninori Morimoto 
5990b73ba55SKuninori Morimoto 	for_each_rtd_dais(rtd, i, dai) {
600624fee45SKuninori Morimoto 		if (dai->driver->ops &&
601624fee45SKuninori Morimoto 		    dai->driver->ops->pcm_new) {
602624fee45SKuninori Morimoto 			int ret = dai->driver->ops->pcm_new(rtd, dai);
6030b73ba55SKuninori Morimoto 			if (ret < 0)
6040b73ba55SKuninori Morimoto 				return soc_dai_ret(dai, ret);
6050b73ba55SKuninori Morimoto 		}
6060b73ba55SKuninori Morimoto 	}
6070b73ba55SKuninori Morimoto 
6080b73ba55SKuninori Morimoto 	return 0;
6090b73ba55SKuninori Morimoto }
610d108c7fdSKuninori Morimoto 
snd_soc_pcm_dai_prepare(struct snd_pcm_substream * substream)611d108c7fdSKuninori Morimoto int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream)
612d108c7fdSKuninori Morimoto {
6130ceef681SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
614d108c7fdSKuninori Morimoto 	struct snd_soc_dai *dai;
615d108c7fdSKuninori Morimoto 	int i, ret;
616d108c7fdSKuninori Morimoto 
617d108c7fdSKuninori Morimoto 	for_each_rtd_dais(rtd, i, dai) {
6184005d1baSPeter Suti 		if (!snd_soc_dai_stream_valid(dai, substream->stream))
6194005d1baSPeter Suti 			continue;
620d108c7fdSKuninori Morimoto 		if (dai->driver->ops &&
621d108c7fdSKuninori Morimoto 		    dai->driver->ops->prepare) {
622d108c7fdSKuninori Morimoto 			ret = dai->driver->ops->prepare(substream, dai);
623d108c7fdSKuninori Morimoto 			if (ret < 0)
624d108c7fdSKuninori Morimoto 				return soc_dai_ret(dai, ret);
625d108c7fdSKuninori Morimoto 		}
626d108c7fdSKuninori Morimoto 	}
627d108c7fdSKuninori Morimoto 
628d108c7fdSKuninori Morimoto 	return 0;
629d108c7fdSKuninori Morimoto }
63042f2472dSKuninori Morimoto 
soc_dai_trigger(struct snd_soc_dai * dai,struct snd_pcm_substream * substream,int cmd)6316374f493SKuninori Morimoto static int soc_dai_trigger(struct snd_soc_dai *dai,
6326374f493SKuninori Morimoto 			   struct snd_pcm_substream *substream, int cmd)
6336374f493SKuninori Morimoto {
6346374f493SKuninori Morimoto 	int ret = 0;
6356374f493SKuninori Morimoto 
6364005d1baSPeter Suti 	if (!snd_soc_dai_stream_valid(dai, substream->stream))
6374005d1baSPeter Suti 		return 0;
6384005d1baSPeter Suti 
6396374f493SKuninori Morimoto 	if (dai->driver->ops &&
6406374f493SKuninori Morimoto 	    dai->driver->ops->trigger)
6416374f493SKuninori Morimoto 		ret = dai->driver->ops->trigger(substream, cmd, dai);
6426374f493SKuninori Morimoto 
6436374f493SKuninori Morimoto 	return soc_dai_ret(dai, ret);
6446374f493SKuninori Morimoto }
6456374f493SKuninori Morimoto 
snd_soc_pcm_dai_trigger(struct snd_pcm_substream * substream,int cmd,int rollback)64642f2472dSKuninori Morimoto int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream,
6476374f493SKuninori Morimoto 			    int cmd, int rollback)
64842f2472dSKuninori Morimoto {
6490ceef681SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
65042f2472dSKuninori Morimoto 	struct snd_soc_dai *dai;
6516374f493SKuninori Morimoto 	int i, r, ret = 0;
65242f2472dSKuninori Morimoto 
6536374f493SKuninori Morimoto 	switch (cmd) {
6546374f493SKuninori Morimoto 	case SNDRV_PCM_TRIGGER_START:
6556374f493SKuninori Morimoto 	case SNDRV_PCM_TRIGGER_RESUME:
6566374f493SKuninori Morimoto 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
65742f2472dSKuninori Morimoto 		for_each_rtd_dais(rtd, i, dai) {
6586374f493SKuninori Morimoto 			ret = soc_dai_trigger(dai, substream, cmd);
65942f2472dSKuninori Morimoto 			if (ret < 0)
6606374f493SKuninori Morimoto 				break;
661*868eb92bSSrinivas Kandagatla 
662*868eb92bSSrinivas Kandagatla 			if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger)
663*868eb92bSSrinivas Kandagatla 				snd_soc_dai_digital_mute(dai, 0, substream->stream);
664*868eb92bSSrinivas Kandagatla 
6656374f493SKuninori Morimoto 			soc_dai_mark_push(dai, substream, trigger);
6666374f493SKuninori Morimoto 		}
6676374f493SKuninori Morimoto 		break;
6686374f493SKuninori Morimoto 	case SNDRV_PCM_TRIGGER_STOP:
6696374f493SKuninori Morimoto 	case SNDRV_PCM_TRIGGER_SUSPEND:
6706374f493SKuninori Morimoto 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
6716374f493SKuninori Morimoto 		for_each_rtd_dais(rtd, i, dai) {
6726374f493SKuninori Morimoto 			if (rollback && !soc_dai_mark_match(dai, substream, trigger))
6736374f493SKuninori Morimoto 				continue;
6746374f493SKuninori Morimoto 
675*868eb92bSSrinivas Kandagatla 			if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger)
676*868eb92bSSrinivas Kandagatla 				snd_soc_dai_digital_mute(dai, 1, substream->stream);
677*868eb92bSSrinivas Kandagatla 
6786374f493SKuninori Morimoto 			r = soc_dai_trigger(dai, substream, cmd);
6796374f493SKuninori Morimoto 			if (r < 0)
6806374f493SKuninori Morimoto 				ret = r; /* use last ret */
6816374f493SKuninori Morimoto 			soc_dai_mark_pop(dai, substream, trigger);
68242f2472dSKuninori Morimoto 		}
68342f2472dSKuninori Morimoto 	}
68442f2472dSKuninori Morimoto 
6856374f493SKuninori Morimoto 	return ret;
68642f2472dSKuninori Morimoto }
68730819358SKuninori Morimoto 
snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream * substream,int cmd)68830819358SKuninori Morimoto int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
68930819358SKuninori Morimoto 				    int cmd)
69030819358SKuninori Morimoto {
6910ceef681SKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
69230819358SKuninori Morimoto 	struct snd_soc_dai *dai;
69330819358SKuninori Morimoto 	int i, ret;
69430819358SKuninori Morimoto 
69530819358SKuninori Morimoto 	for_each_rtd_dais(rtd, i, dai) {
69630819358SKuninori Morimoto 		if (dai->driver->ops &&
69730819358SKuninori Morimoto 		    dai->driver->ops->bespoke_trigger) {
69830819358SKuninori Morimoto 			ret = dai->driver->ops->bespoke_trigger(substream,
69930819358SKuninori Morimoto 								cmd, dai);
70030819358SKuninori Morimoto 			if (ret < 0)
70130819358SKuninori Morimoto 				return soc_dai_ret(dai, ret);
70230819358SKuninori Morimoto 		}
70330819358SKuninori Morimoto 	}
70430819358SKuninori Morimoto 
70530819358SKuninori Morimoto 	return 0;
70630819358SKuninori Morimoto }
707b5ae4cceSKuninori Morimoto 
snd_soc_pcm_dai_delay(struct snd_pcm_substream * substream,snd_pcm_sframes_t * cpu_delay,snd_pcm_sframes_t * codec_delay)7088544f08cSKuninori Morimoto void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
7098544f08cSKuninori Morimoto 			   snd_pcm_sframes_t *cpu_delay,
7108544f08cSKuninori Morimoto 			   snd_pcm_sframes_t *codec_delay)
7118544f08cSKuninori Morimoto {
7128544f08cSKuninori Morimoto 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
7138544f08cSKuninori Morimoto 	struct snd_soc_dai *dai;
7148544f08cSKuninori Morimoto 	int i;
7158544f08cSKuninori Morimoto 
7168544f08cSKuninori Morimoto 	/*
7178544f08cSKuninori Morimoto 	 * We're looking for the delay through the full audio path so it needs to
7188544f08cSKuninori Morimoto 	 * be the maximum of the DAIs doing transmit and the maximum of the DAIs
7198544f08cSKuninori Morimoto 	 * doing receive (ie, all CPUs and all CODECs) rather than just the maximum
7208544f08cSKuninori Morimoto 	 * of all DAIs.
7218544f08cSKuninori Morimoto 	 */
7228544f08cSKuninori Morimoto 
7238544f08cSKuninori Morimoto 	/* for CPU */
7248544f08cSKuninori Morimoto 	for_each_rtd_cpu_dais(rtd, i, dai)
7258544f08cSKuninori Morimoto 		if (dai->driver->ops &&
7268544f08cSKuninori Morimoto 		    dai->driver->ops->delay)
7278544f08cSKuninori Morimoto 			*cpu_delay = max(*cpu_delay, dai->driver->ops->delay(substream, dai));
7288544f08cSKuninori Morimoto 
7298544f08cSKuninori Morimoto 	/* for Codec */
7308544f08cSKuninori Morimoto 	for_each_rtd_codec_dais(rtd, i, dai)
7318544f08cSKuninori Morimoto 		if (dai->driver->ops &&
7328544f08cSKuninori Morimoto 		    dai->driver->ops->delay)
7338544f08cSKuninori Morimoto 			*codec_delay = max(*codec_delay, dai->driver->ops->delay(substream, dai));
7348544f08cSKuninori Morimoto }
7358544f08cSKuninori Morimoto 
snd_soc_dai_compr_startup(struct snd_soc_dai * dai,struct snd_compr_stream * cstream)736b5ae4cceSKuninori Morimoto int snd_soc_dai_compr_startup(struct snd_soc_dai *dai,
737b5ae4cceSKuninori Morimoto 			      struct snd_compr_stream *cstream)
738b5ae4cceSKuninori Morimoto {
739b5ae4cceSKuninori Morimoto 	int ret = 0;
740b5ae4cceSKuninori Morimoto 
741b5ae4cceSKuninori Morimoto 	if (dai->driver->cops &&
742b5ae4cceSKuninori Morimoto 	    dai->driver->cops->startup)
743b5ae4cceSKuninori Morimoto 		ret = dai->driver->cops->startup(cstream, dai);
744b5ae4cceSKuninori Morimoto 
7451e6a93cfSKuninori Morimoto 	/* mark cstream if succeeded */
7461e6a93cfSKuninori Morimoto 	if (ret == 0)
7471e6a93cfSKuninori Morimoto 		soc_dai_mark_push(dai, cstream, compr_startup);
7481e6a93cfSKuninori Morimoto 
749b5ae4cceSKuninori Morimoto 	return soc_dai_ret(dai, ret);
750b5ae4cceSKuninori Morimoto }
751b5ae4cceSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_startup);
7522b25f81dSKuninori Morimoto 
snd_soc_dai_compr_shutdown(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,int rollback)7532b25f81dSKuninori Morimoto void snd_soc_dai_compr_shutdown(struct snd_soc_dai *dai,
7541e6a93cfSKuninori Morimoto 				struct snd_compr_stream *cstream,
7551e6a93cfSKuninori Morimoto 				int rollback)
7562b25f81dSKuninori Morimoto {
7571e6a93cfSKuninori Morimoto 	if (rollback && !soc_dai_mark_match(dai, cstream, compr_startup))
7581e6a93cfSKuninori Morimoto 		return;
7591e6a93cfSKuninori Morimoto 
7602b25f81dSKuninori Morimoto 	if (dai->driver->cops &&
7612b25f81dSKuninori Morimoto 	    dai->driver->cops->shutdown)
7622b25f81dSKuninori Morimoto 		dai->driver->cops->shutdown(cstream, dai);
7631e6a93cfSKuninori Morimoto 
7641e6a93cfSKuninori Morimoto 	/* remove marked cstream */
7651e6a93cfSKuninori Morimoto 	soc_dai_mark_pop(dai, cstream, compr_startup);
7662b25f81dSKuninori Morimoto }
7672b25f81dSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_shutdown);
768eb08411bSKuninori Morimoto 
snd_soc_dai_compr_trigger(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,int cmd)769eb08411bSKuninori Morimoto int snd_soc_dai_compr_trigger(struct snd_soc_dai *dai,
770eb08411bSKuninori Morimoto 			      struct snd_compr_stream *cstream, int cmd)
771eb08411bSKuninori Morimoto {
772eb08411bSKuninori Morimoto 	int ret = 0;
773eb08411bSKuninori Morimoto 
774eb08411bSKuninori Morimoto 	if (dai->driver->cops &&
775eb08411bSKuninori Morimoto 	    dai->driver->cops->trigger)
776eb08411bSKuninori Morimoto 		ret = dai->driver->cops->trigger(cstream, cmd, dai);
777eb08411bSKuninori Morimoto 
778eb08411bSKuninori Morimoto 	return soc_dai_ret(dai, ret);
779eb08411bSKuninori Morimoto }
780eb08411bSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_trigger);
7818dfedafbSKuninori Morimoto 
snd_soc_dai_compr_set_params(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_params * params)7828dfedafbSKuninori Morimoto int snd_soc_dai_compr_set_params(struct snd_soc_dai *dai,
7838dfedafbSKuninori Morimoto 				 struct snd_compr_stream *cstream,
7848dfedafbSKuninori Morimoto 				 struct snd_compr_params *params)
7858dfedafbSKuninori Morimoto {
7868dfedafbSKuninori Morimoto 	int ret = 0;
7878dfedafbSKuninori Morimoto 
7888dfedafbSKuninori Morimoto 	if (dai->driver->cops &&
7898dfedafbSKuninori Morimoto 	    dai->driver->cops->set_params)
7908dfedafbSKuninori Morimoto 		ret = dai->driver->cops->set_params(cstream, params, dai);
7918dfedafbSKuninori Morimoto 
7928dfedafbSKuninori Morimoto 	return soc_dai_ret(dai, ret);
7938dfedafbSKuninori Morimoto }
7948dfedafbSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_params);
795adbef543SKuninori Morimoto 
snd_soc_dai_compr_get_params(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_codec * params)796adbef543SKuninori Morimoto int snd_soc_dai_compr_get_params(struct snd_soc_dai *dai,
797adbef543SKuninori Morimoto 				 struct snd_compr_stream *cstream,
798adbef543SKuninori Morimoto 				 struct snd_codec *params)
799adbef543SKuninori Morimoto {
800adbef543SKuninori Morimoto 	int ret = 0;
801adbef543SKuninori Morimoto 
802adbef543SKuninori Morimoto 	if (dai->driver->cops &&
803adbef543SKuninori Morimoto 	    dai->driver->cops->get_params)
804adbef543SKuninori Morimoto 		ret = dai->driver->cops->get_params(cstream, params, dai);
805adbef543SKuninori Morimoto 
806adbef543SKuninori Morimoto 	return soc_dai_ret(dai, ret);
807adbef543SKuninori Morimoto }
808adbef543SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_params);
80953294353SKuninori Morimoto 
snd_soc_dai_compr_ack(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,size_t bytes)81053294353SKuninori Morimoto int snd_soc_dai_compr_ack(struct snd_soc_dai *dai,
81153294353SKuninori Morimoto 			  struct snd_compr_stream *cstream,
81253294353SKuninori Morimoto 			  size_t bytes)
81353294353SKuninori Morimoto {
81453294353SKuninori Morimoto 	int ret = 0;
81553294353SKuninori Morimoto 
81653294353SKuninori Morimoto 	if (dai->driver->cops &&
81753294353SKuninori Morimoto 	    dai->driver->cops->ack)
81853294353SKuninori Morimoto 		ret = dai->driver->cops->ack(cstream, bytes, dai);
81953294353SKuninori Morimoto 
82053294353SKuninori Morimoto 	return soc_dai_ret(dai, ret);
82153294353SKuninori Morimoto }
82253294353SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_ack);
823ed38cc59SKuninori Morimoto 
snd_soc_dai_compr_pointer(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_tstamp * tstamp)824ed38cc59SKuninori Morimoto int snd_soc_dai_compr_pointer(struct snd_soc_dai *dai,
825ed38cc59SKuninori Morimoto 			      struct snd_compr_stream *cstream,
826ed38cc59SKuninori Morimoto 			      struct snd_compr_tstamp *tstamp)
827ed38cc59SKuninori Morimoto {
828ed38cc59SKuninori Morimoto 	int ret = 0;
829ed38cc59SKuninori Morimoto 
830ed38cc59SKuninori Morimoto 	if (dai->driver->cops &&
831ed38cc59SKuninori Morimoto 	    dai->driver->cops->pointer)
832ed38cc59SKuninori Morimoto 		ret = dai->driver->cops->pointer(cstream, tstamp, dai);
833ed38cc59SKuninori Morimoto 
834ed38cc59SKuninori Morimoto 	return soc_dai_ret(dai, ret);
835ed38cc59SKuninori Morimoto }
836ed38cc59SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_pointer);
83788b3a7dfSKuninori Morimoto 
snd_soc_dai_compr_set_metadata(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)83888b3a7dfSKuninori Morimoto int snd_soc_dai_compr_set_metadata(struct snd_soc_dai *dai,
83988b3a7dfSKuninori Morimoto 				   struct snd_compr_stream *cstream,
84088b3a7dfSKuninori Morimoto 				   struct snd_compr_metadata *metadata)
84188b3a7dfSKuninori Morimoto {
84288b3a7dfSKuninori Morimoto 	int ret = 0;
84388b3a7dfSKuninori Morimoto 
84488b3a7dfSKuninori Morimoto 	if (dai->driver->cops &&
84588b3a7dfSKuninori Morimoto 	    dai->driver->cops->set_metadata)
84688b3a7dfSKuninori Morimoto 		ret = dai->driver->cops->set_metadata(cstream, metadata, dai);
84788b3a7dfSKuninori Morimoto 
84888b3a7dfSKuninori Morimoto 	return soc_dai_ret(dai, ret);
84988b3a7dfSKuninori Morimoto }
85088b3a7dfSKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_set_metadata);
85194d72819SKuninori Morimoto 
snd_soc_dai_compr_get_metadata(struct snd_soc_dai * dai,struct snd_compr_stream * cstream,struct snd_compr_metadata * metadata)85294d72819SKuninori Morimoto int snd_soc_dai_compr_get_metadata(struct snd_soc_dai *dai,
85394d72819SKuninori Morimoto 				   struct snd_compr_stream *cstream,
85494d72819SKuninori Morimoto 				   struct snd_compr_metadata *metadata)
85594d72819SKuninori Morimoto {
85694d72819SKuninori Morimoto 	int ret = 0;
85794d72819SKuninori Morimoto 
85894d72819SKuninori Morimoto 	if (dai->driver->cops &&
85994d72819SKuninori Morimoto 	    dai->driver->cops->get_metadata)
86094d72819SKuninori Morimoto 		ret = dai->driver->cops->get_metadata(cstream, metadata, dai);
86194d72819SKuninori Morimoto 
86294d72819SKuninori Morimoto 	return soc_dai_ret(dai, ret);
86394d72819SKuninori Morimoto }
86494d72819SKuninori Morimoto EXPORT_SYMBOL_GPL(snd_soc_dai_compr_get_metadata);
865