root/sound/arm/pxa2xx-pcm-lib.c

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

DEFINITIONS

This source file includes following definitions.
  1. pxa2xx_pcm_hw_params
  2. pxa2xx_pcm_hw_free
  3. pxa2xx_pcm_trigger
  4. pxa2xx_pcm_pointer
  5. pxa2xx_pcm_prepare
  6. pxa2xx_pcm_open
  7. pxa2xx_pcm_close
  8. pxa2xx_pcm_mmap
  9. pxa2xx_pcm_preallocate_dma_buffer
  10. pxa2xx_pcm_free_dma_buffers
  11. pxa2xx_soc_pcm_new

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 
   3 #include <linux/slab.h>
   4 #include <linux/module.h>
   5 #include <linux/dma-mapping.h>
   6 #include <linux/dmaengine.h>
   7 #include <linux/dma/pxa-dma.h>
   8 
   9 #include <sound/core.h>
  10 #include <sound/pcm.h>
  11 #include <sound/pcm_params.h>
  12 #include <sound/pxa2xx-lib.h>
  13 #include <sound/dmaengine_pcm.h>
  14 
  15 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
  16         .info                   = SNDRV_PCM_INFO_MMAP |
  17                                   SNDRV_PCM_INFO_MMAP_VALID |
  18                                   SNDRV_PCM_INFO_INTERLEAVED |
  19                                   SNDRV_PCM_INFO_PAUSE |
  20                                   SNDRV_PCM_INFO_RESUME,
  21         .formats                = SNDRV_PCM_FMTBIT_S16_LE |
  22                                   SNDRV_PCM_FMTBIT_S24_LE |
  23                                   SNDRV_PCM_FMTBIT_S32_LE,
  24         .period_bytes_min       = 32,
  25         .period_bytes_max       = 8192 - 32,
  26         .periods_min            = 1,
  27         .periods_max            = 256,
  28         .buffer_bytes_max       = 128 * 1024,
  29         .fifo_size              = 32,
  30 };
  31 
  32 int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
  33                          struct snd_pcm_hw_params *params)
  34 {
  35         struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
  36         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  37         struct snd_dmaengine_dai_dma_data *dma_params;
  38         struct dma_slave_config config;
  39         int ret;
  40 
  41         dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
  42         if (!dma_params)
  43                 return 0;
  44 
  45         ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
  46         if (ret)
  47                 return ret;
  48 
  49         snd_dmaengine_pcm_set_config_from_dai_data(substream,
  50                         snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
  51                         &config);
  52 
  53         ret = dmaengine_slave_config(chan, &config);
  54         if (ret)
  55                 return ret;
  56 
  57         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
  58 
  59         return 0;
  60 }
  61 EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
  62 
  63 int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
  64 {
  65         snd_pcm_set_runtime_buffer(substream, NULL);
  66         return 0;
  67 }
  68 EXPORT_SYMBOL(pxa2xx_pcm_hw_free);
  69 
  70 int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  71 {
  72         return snd_dmaengine_pcm_trigger(substream, cmd);
  73 }
  74 EXPORT_SYMBOL(pxa2xx_pcm_trigger);
  75 
  76 snd_pcm_uframes_t
  77 pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
  78 {
  79         return snd_dmaengine_pcm_pointer(substream);
  80 }
  81 EXPORT_SYMBOL(pxa2xx_pcm_pointer);
  82 
  83 int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
  84 {
  85         return 0;
  86 }
  87 EXPORT_SYMBOL(pxa2xx_pcm_prepare);
  88 
  89 int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
  90 {
  91         struct snd_soc_pcm_runtime *rtd = substream->private_data;
  92         struct snd_pcm_runtime *runtime = substream->runtime;
  93         struct snd_dmaengine_dai_dma_data *dma_params;
  94         int ret;
  95 
  96         runtime->hw = pxa2xx_pcm_hardware;
  97 
  98         dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
  99         if (!dma_params)
 100                 return 0;
 101 
 102         /*
 103          * For mysterious reasons (and despite what the manual says)
 104          * playback samples are lost if the DMA count is not a multiple
 105          * of the DMA burst size.  Let's add a rule to enforce that.
 106          */
 107         ret = snd_pcm_hw_constraint_step(runtime, 0,
 108                 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
 109         if (ret)
 110                 return ret;
 111 
 112         ret = snd_pcm_hw_constraint_step(runtime, 0,
 113                 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
 114         if (ret)
 115                 return ret;
 116 
 117         ret = snd_pcm_hw_constraint_integer(runtime,
 118                                             SNDRV_PCM_HW_PARAM_PERIODS);
 119         if (ret < 0)
 120                 return ret;
 121 
 122         return snd_dmaengine_pcm_open(
 123                 substream, dma_request_slave_channel(rtd->cpu_dai->dev,
 124                                                      dma_params->chan_name));
 125 }
 126 EXPORT_SYMBOL(pxa2xx_pcm_open);
 127 
 128 int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 129 {
 130         return snd_dmaengine_pcm_close_release_chan(substream);
 131 }
 132 EXPORT_SYMBOL(pxa2xx_pcm_close);
 133 
 134 int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
 135         struct vm_area_struct *vma)
 136 {
 137         struct snd_pcm_runtime *runtime = substream->runtime;
 138         return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
 139                            runtime->dma_addr, runtime->dma_bytes);
 140 }
 141 EXPORT_SYMBOL(pxa2xx_pcm_mmap);
 142 
 143 int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 144 {
 145         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 146         struct snd_dma_buffer *buf = &substream->dma_buffer;
 147         size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
 148         buf->dev.type = SNDRV_DMA_TYPE_DEV;
 149         buf->dev.dev = pcm->card->dev;
 150         buf->private_data = NULL;
 151         buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
 152         if (!buf->area)
 153                 return -ENOMEM;
 154         buf->bytes = size;
 155         return 0;
 156 }
 157 EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
 158 
 159 void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 160 {
 161         struct snd_pcm_substream *substream;
 162         struct snd_dma_buffer *buf;
 163         int stream;
 164 
 165         for (stream = 0; stream < 2; stream++) {
 166                 substream = pcm->streams[stream].substream;
 167                 if (!substream)
 168                         continue;
 169                 buf = &substream->dma_buffer;
 170                 if (!buf->area)
 171                         continue;
 172                 dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
 173                 buf->area = NULL;
 174         }
 175 }
 176 EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
 177 
 178 int pxa2xx_soc_pcm_new(struct snd_soc_pcm_runtime *rtd)
 179 {
 180         struct snd_card *card = rtd->card->snd_card;
 181         struct snd_pcm *pcm = rtd->pcm;
 182         int ret;
 183 
 184         ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
 185         if (ret)
 186                 return ret;
 187 
 188         if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
 189                 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
 190                         SNDRV_PCM_STREAM_PLAYBACK);
 191                 if (ret)
 192                         goto out;
 193         }
 194 
 195         if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
 196                 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
 197                         SNDRV_PCM_STREAM_CAPTURE);
 198                 if (ret)
 199                         goto out;
 200         }
 201  out:
 202         return ret;
 203 }
 204 EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
 205 
 206 const struct snd_pcm_ops pxa2xx_pcm_ops = {
 207         .open           = pxa2xx_pcm_open,
 208         .close          = pxa2xx_pcm_close,
 209         .ioctl          = snd_pcm_lib_ioctl,
 210         .hw_params      = pxa2xx_pcm_hw_params,
 211         .hw_free        = pxa2xx_pcm_hw_free,
 212         .prepare        = pxa2xx_pcm_prepare,
 213         .trigger        = pxa2xx_pcm_trigger,
 214         .pointer        = pxa2xx_pcm_pointer,
 215         .mmap           = pxa2xx_pcm_mmap,
 216 };
 217 EXPORT_SYMBOL(pxa2xx_pcm_ops);
 218 
 219 MODULE_AUTHOR("Nicolas Pitre");
 220 MODULE_DESCRIPTION("Intel PXA2xx sound library");
 221 MODULE_LICENSE("GPL");

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