root/sound/soc/soc-dai.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. snd_soc_dai_set_sysclk
  2. snd_soc_dai_set_clkdiv
  3. snd_soc_dai_set_pll
  4. snd_soc_dai_set_bclk_ratio
  5. snd_soc_dai_set_fmt
  6. snd_soc_xlate_tdm_slot_mask
  7. snd_soc_dai_set_tdm_slot
  8. snd_soc_dai_set_channel_map
  9. snd_soc_dai_get_channel_map
  10. snd_soc_dai_set_tristate
  11. snd_soc_dai_digital_mute
  12. snd_soc_dai_hw_params
  13. snd_soc_dai_hw_free
  14. snd_soc_dai_startup
  15. snd_soc_dai_shutdown
  16. snd_soc_dai_prepare
  17. snd_soc_dai_trigger
  18. snd_soc_dai_bespoke_trigger
  19. snd_soc_dai_delay
  20. snd_soc_dai_suspend
  21. snd_soc_dai_resume
  22. snd_soc_dai_probe
  23. snd_soc_dai_remove
  24. snd_soc_dai_compress_new
  25. snd_soc_dai_stream_valid

   1 // SPDX-License-Identifier: GPL-2.0
   2 //
   3 // soc-dai.c
   4 //
   5 // Copyright (C) 2019 Renesas Electronics Corp.
   6 // Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
   7 //
   8 
   9 #include <sound/soc.h>
  10 #include <sound/soc-dai.h>
  11 
  12 /**
  13  * snd_soc_dai_set_sysclk - configure DAI system or master clock.
  14  * @dai: DAI
  15  * @clk_id: DAI specific clock ID
  16  * @freq: new clock frequency in Hz
  17  * @dir: new clock direction - input/output.
  18  *
  19  * Configures the DAI master (MCLK) or system (SYSCLK) clocking.
  20  */
  21 int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id,
  22                            unsigned int freq, int dir)
  23 {
  24         if (dai->driver->ops->set_sysclk)
  25                 return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir);
  26 
  27         return snd_soc_component_set_sysclk(dai->component, clk_id, 0,
  28                                             freq, dir);
  29 }
  30 EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk);
  31 
  32 /**
  33  * snd_soc_dai_set_clkdiv - configure DAI clock dividers.
  34  * @dai: DAI
  35  * @div_id: DAI specific clock divider ID
  36  * @div: new clock divisor.
  37  *
  38  * Configures the clock dividers. This is used to derive the best DAI bit and
  39  * frame clocks from the system or master clock. It's best to set the DAI bit
  40  * and frame clocks as low as possible to save system power.
  41  */
  42 int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai,
  43                            int div_id, int div)
  44 {
  45         if (dai->driver->ops->set_clkdiv)
  46                 return dai->driver->ops->set_clkdiv(dai, div_id, div);
  47         else
  48                 return -EINVAL;
  49 }
  50 EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv);
  51 
  52 /**
  53  * snd_soc_dai_set_pll - configure DAI PLL.
  54  * @dai: DAI
  55  * @pll_id: DAI specific PLL ID
  56  * @source: DAI specific source for the PLL
  57  * @freq_in: PLL input clock frequency in Hz
  58  * @freq_out: requested PLL output clock frequency in Hz
  59  *
  60  * Configures and enables PLL to generate output clock based on input clock.
  61  */
  62 int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source,
  63                         unsigned int freq_in, unsigned int freq_out)
  64 {
  65         if (dai->driver->ops->set_pll)
  66                 return dai->driver->ops->set_pll(dai, pll_id, source,
  67                                                  freq_in, freq_out);
  68 
  69         return snd_soc_component_set_pll(dai->component, pll_id, source,
  70                                          freq_in, freq_out);
  71 }
  72 EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll);
  73 
  74 /**
  75  * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio.
  76  * @dai: DAI
  77  * @ratio: Ratio of BCLK to Sample rate.
  78  *
  79  * Configures the DAI for a preset BCLK to sample rate ratio.
  80  */
  81 int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio)
  82 {
  83         if (dai->driver->ops->set_bclk_ratio)
  84                 return dai->driver->ops->set_bclk_ratio(dai, ratio);
  85         else
  86                 return -EINVAL;
  87 }
  88 EXPORT_SYMBOL_GPL(snd_soc_dai_set_bclk_ratio);
  89 
  90 /**
  91  * snd_soc_dai_set_fmt - configure DAI hardware audio format.
  92  * @dai: DAI
  93  * @fmt: SND_SOC_DAIFMT_* format value.
  94  *
  95  * Configures the DAI hardware format and clocking.
  96  */
  97 int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  98 {
  99         if (dai->driver->ops->set_fmt == NULL)
 100                 return -ENOTSUPP;
 101         return dai->driver->ops->set_fmt(dai, fmt);
 102 }
 103 EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt);
 104 
 105 /**
 106  * snd_soc_xlate_tdm_slot - generate tx/rx slot mask.
 107  * @slots: Number of slots in use.
 108  * @tx_mask: bitmask representing active TX slots.
 109  * @rx_mask: bitmask representing active RX slots.
 110  *
 111  * Generates the TDM tx and rx slot default masks for DAI.
 112  */
 113 static int snd_soc_xlate_tdm_slot_mask(unsigned int slots,
 114                                        unsigned int *tx_mask,
 115                                        unsigned int *rx_mask)
 116 {
 117         if (*tx_mask || *rx_mask)
 118                 return 0;
 119 
 120         if (!slots)
 121                 return -EINVAL;
 122 
 123         *tx_mask = (1 << slots) - 1;
 124         *rx_mask = (1 << slots) - 1;
 125 
 126         return 0;
 127 }
 128 
 129 /**
 130  * snd_soc_dai_set_tdm_slot() - Configures a DAI for TDM operation
 131  * @dai: The DAI to configure
 132  * @tx_mask: bitmask representing active TX slots.
 133  * @rx_mask: bitmask representing active RX slots.
 134  * @slots: Number of slots in use.
 135  * @slot_width: Width in bits for each slot.
 136  *
 137  * This function configures the specified DAI for TDM operation. @slot contains
 138  * the total number of slots of the TDM stream and @slot_with the width of each
 139  * slot in bit clock cycles. @tx_mask and @rx_mask are bitmasks specifying the
 140  * active slots of the TDM stream for the specified DAI, i.e. which slots the
 141  * DAI should write to or read from. If a bit is set the corresponding slot is
 142  * active, if a bit is cleared the corresponding slot is inactive. Bit 0 maps to
 143  * the first slot, bit 1 to the second slot and so on. The first active slot
 144  * maps to the first channel of the DAI, the second active slot to the second
 145  * channel and so on.
 146  *
 147  * TDM mode can be disabled by passing 0 for @slots. In this case @tx_mask,
 148  * @rx_mask and @slot_width will be ignored.
 149  *
 150  * Returns 0 on success, a negative error code otherwise.
 151  */
 152 int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
 153                              unsigned int tx_mask, unsigned int rx_mask,
 154                              int slots, int slot_width)
 155 {
 156         if (dai->driver->ops->xlate_tdm_slot_mask)
 157                 dai->driver->ops->xlate_tdm_slot_mask(slots,
 158                                                       &tx_mask, &rx_mask);
 159         else
 160                 snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask);
 161 
 162         dai->tx_mask = tx_mask;
 163         dai->rx_mask = rx_mask;
 164 
 165         if (dai->driver->ops->set_tdm_slot)
 166                 return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask,
 167                                                       slots, slot_width);
 168         else
 169                 return -ENOTSUPP;
 170 }
 171 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot);
 172 
 173 /**
 174  * snd_soc_dai_set_channel_map - configure DAI audio channel map
 175  * @dai: DAI
 176  * @tx_num: how many TX channels
 177  * @tx_slot: pointer to an array which imply the TX slot number channel
 178  *           0~num-1 uses
 179  * @rx_num: how many RX channels
 180  * @rx_slot: pointer to an array which imply the RX slot number channel
 181  *           0~num-1 uses
 182  *
 183  * configure the relationship between channel number and TDM slot number.
 184  */
 185 int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai,
 186                                 unsigned int tx_num, unsigned int *tx_slot,
 187                                 unsigned int rx_num, unsigned int *rx_slot)
 188 {
 189         if (dai->driver->ops->set_channel_map)
 190                 return dai->driver->ops->set_channel_map(dai, tx_num, tx_slot,
 191                                                          rx_num, rx_slot);
 192         else
 193                 return -ENOTSUPP;
 194 }
 195 EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map);
 196 
 197 /**
 198  * snd_soc_dai_get_channel_map - Get DAI audio channel map
 199  * @dai: DAI
 200  * @tx_num: how many TX channels
 201  * @tx_slot: pointer to an array which imply the TX slot number channel
 202  *           0~num-1 uses
 203  * @rx_num: how many RX channels
 204  * @rx_slot: pointer to an array which imply the RX slot number channel
 205  *           0~num-1 uses
 206  */
 207 int snd_soc_dai_get_channel_map(struct snd_soc_dai *dai,
 208                                 unsigned int *tx_num, unsigned int *tx_slot,
 209                                 unsigned int *rx_num, unsigned int *rx_slot)
 210 {
 211         if (dai->driver->ops->get_channel_map)
 212                 return dai->driver->ops->get_channel_map(dai, tx_num, tx_slot,
 213                                                          rx_num, rx_slot);
 214         else
 215                 return -ENOTSUPP;
 216 }
 217 EXPORT_SYMBOL_GPL(snd_soc_dai_get_channel_map);
 218 
 219 /**
 220  * snd_soc_dai_set_tristate - configure DAI system or master clock.
 221  * @dai: DAI
 222  * @tristate: tristate enable
 223  *
 224  * Tristates the DAI so that others can use it.
 225  */
 226 int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate)
 227 {
 228         if (dai->driver->ops->set_tristate)
 229                 return dai->driver->ops->set_tristate(dai, tristate);
 230         else
 231                 return -EINVAL;
 232 }
 233 EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate);
 234 
 235 /**
 236  * snd_soc_dai_digital_mute - configure DAI system or master clock.
 237  * @dai: DAI
 238  * @mute: mute enable
 239  * @direction: stream to mute
 240  *
 241  * Mutes the DAI DAC.
 242  */
 243 int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute,
 244                              int direction)
 245 {
 246         if (dai->driver->ops->mute_stream)
 247                 return dai->driver->ops->mute_stream(dai, mute, direction);
 248         else if (direction == SNDRV_PCM_STREAM_PLAYBACK &&
 249                  dai->driver->ops->digital_mute)
 250                 return dai->driver->ops->digital_mute(dai, mute);
 251         else
 252                 return -ENOTSUPP;
 253 }
 254 EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute);
 255 
 256 int snd_soc_dai_hw_params(struct snd_soc_dai *dai,
 257                           struct snd_pcm_substream *substream,
 258                           struct snd_pcm_hw_params *params)
 259 {
 260         struct snd_soc_pcm_runtime *rtd = substream->private_data;
 261         int ret;
 262 
 263         /* perform any topology hw_params fixups before DAI  */
 264         if (rtd->dai_link->be_hw_params_fixup) {
 265                 ret = rtd->dai_link->be_hw_params_fixup(rtd, params);
 266                 if (ret < 0) {
 267                         dev_err(rtd->dev,
 268                                 "ASoC: hw_params topology fixup failed %d\n",
 269                                 ret);
 270                         return ret;
 271                 }
 272         }
 273 
 274         if (dai->driver->ops->hw_params) {
 275                 ret = dai->driver->ops->hw_params(substream, params, dai);
 276                 if (ret < 0) {
 277                         dev_err(dai->dev, "ASoC: can't set %s hw params: %d\n",
 278                                 dai->name, ret);
 279                         return ret;
 280                 }
 281         }
 282 
 283         return 0;
 284 }
 285 
 286 void snd_soc_dai_hw_free(struct snd_soc_dai *dai,
 287                          struct snd_pcm_substream *substream)
 288 {
 289         if (dai->driver->ops->hw_free)
 290                 dai->driver->ops->hw_free(substream, dai);
 291 }
 292 
 293 int snd_soc_dai_startup(struct snd_soc_dai *dai,
 294                         struct snd_pcm_substream *substream)
 295 {
 296         int ret = 0;
 297 
 298         if (dai->driver->ops->startup)
 299                 ret = dai->driver->ops->startup(substream, dai);
 300 
 301         return ret;
 302 }
 303 
 304 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
 305                          struct snd_pcm_substream *substream)
 306 {
 307         if (dai->driver->ops->shutdown)
 308                 dai->driver->ops->shutdown(substream, dai);
 309 }
 310 
 311 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
 312                         struct snd_pcm_substream *substream)
 313 {
 314         int ret = 0;
 315 
 316         if (dai->driver->ops->prepare)
 317                 ret = dai->driver->ops->prepare(substream, dai);
 318 
 319         return ret;
 320 }
 321 
 322 int snd_soc_dai_trigger(struct snd_soc_dai *dai,
 323                         struct snd_pcm_substream *substream,
 324                         int cmd)
 325 {
 326         int ret = 0;
 327 
 328         if (dai->driver->ops->trigger)
 329                 ret = dai->driver->ops->trigger(substream, cmd, dai);
 330 
 331         return ret;
 332 }
 333 
 334 int snd_soc_dai_bespoke_trigger(struct snd_soc_dai *dai,
 335                                 struct snd_pcm_substream *substream,
 336                                 int cmd)
 337 {
 338         int ret = 0;
 339 
 340         if (dai->driver->ops->bespoke_trigger)
 341                 ret = dai->driver->ops->bespoke_trigger(substream, cmd, dai);
 342 
 343         return ret;
 344 }
 345 
 346 snd_pcm_sframes_t snd_soc_dai_delay(struct snd_soc_dai *dai,
 347                                     struct snd_pcm_substream *substream)
 348 {
 349         int delay = 0;
 350 
 351         if (dai->driver->ops->delay)
 352                 delay = dai->driver->ops->delay(substream, dai);
 353 
 354         return delay;
 355 }
 356 
 357 void snd_soc_dai_suspend(struct snd_soc_dai *dai)
 358 {
 359         if (dai->driver->suspend)
 360                 dai->driver->suspend(dai);
 361 }
 362 
 363 void snd_soc_dai_resume(struct snd_soc_dai *dai)
 364 {
 365         if (dai->driver->resume)
 366                 dai->driver->resume(dai);
 367 }
 368 
 369 int snd_soc_dai_probe(struct snd_soc_dai *dai)
 370 {
 371         if (dai->driver->probe)
 372                 return dai->driver->probe(dai);
 373         return 0;
 374 }
 375 
 376 int snd_soc_dai_remove(struct snd_soc_dai *dai)
 377 {
 378         if (dai->driver->remove)
 379                 return dai->driver->remove(dai);
 380         return 0;
 381 }
 382 
 383 int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
 384                              struct snd_soc_pcm_runtime *rtd, int num)
 385 {
 386         if (dai->driver->compress_new)
 387                 return dai->driver->compress_new(rtd, num);
 388         return -ENOTSUPP;
 389 }
 390 
 391 /*
 392  * snd_soc_dai_stream_valid() - check if a DAI supports the given stream
 393  *
 394  * Returns true if the DAI supports the indicated stream type.
 395  */
 396 bool snd_soc_dai_stream_valid(struct snd_soc_dai *dai, int dir)
 397 {
 398         struct snd_soc_pcm_stream *stream;
 399 
 400         if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 401                 stream = &dai->driver->playback;
 402         else
 403                 stream = &dai->driver->capture;
 404 
 405         /* If the codec specifies any channels at all, it supports the stream */
 406         return stream->channels_min;
 407 }

/* [<][>][^][v][top][bottom][index][help] */