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