Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 
0003 #include <linux/slab.h>
0004 #include <linux/module.h>
0005 #include <linux/dma-mapping.h>
0006 #include <linux/dmaengine.h>
0007 #include <linux/dma/pxa-dma.h>
0008 
0009 #include <sound/core.h>
0010 #include <sound/pcm.h>
0011 #include <sound/pcm_params.h>
0012 #include <sound/pxa2xx-lib.h>
0013 #include <sound/dmaengine_pcm.h>
0014 
0015 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
0016     .info           = SNDRV_PCM_INFO_MMAP |
0017                   SNDRV_PCM_INFO_MMAP_VALID |
0018                   SNDRV_PCM_INFO_INTERLEAVED |
0019                   SNDRV_PCM_INFO_PAUSE |
0020                   SNDRV_PCM_INFO_RESUME,
0021     .formats        = SNDRV_PCM_FMTBIT_S16_LE |
0022                   SNDRV_PCM_FMTBIT_S24_LE |
0023                   SNDRV_PCM_FMTBIT_S32_LE,
0024     .period_bytes_min   = 32,
0025     .period_bytes_max   = 8192 - 32,
0026     .periods_min        = 1,
0027     .periods_max        = 256,
0028     .buffer_bytes_max   = 128 * 1024,
0029     .fifo_size      = 32,
0030 };
0031 
0032 int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
0033              struct snd_pcm_hw_params *params)
0034 {
0035     struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
0036     struct snd_soc_pcm_runtime *rtd = substream->private_data;
0037     struct snd_dmaengine_dai_dma_data *dma_params;
0038     struct dma_slave_config config;
0039     int ret;
0040 
0041     dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
0042     if (!dma_params)
0043         return 0;
0044 
0045     ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
0046     if (ret)
0047         return ret;
0048 
0049     snd_dmaengine_pcm_set_config_from_dai_data(substream,
0050             snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream),
0051             &config);
0052 
0053     ret = dmaengine_slave_config(chan, &config);
0054     if (ret)
0055         return ret;
0056 
0057     return 0;
0058 }
0059 EXPORT_SYMBOL(pxa2xx_pcm_hw_params);
0060 
0061 int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
0062 {
0063     return snd_dmaengine_pcm_trigger(substream, cmd);
0064 }
0065 EXPORT_SYMBOL(pxa2xx_pcm_trigger);
0066 
0067 snd_pcm_uframes_t
0068 pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
0069 {
0070     return snd_dmaengine_pcm_pointer(substream);
0071 }
0072 EXPORT_SYMBOL(pxa2xx_pcm_pointer);
0073 
0074 int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
0075 {
0076     return 0;
0077 }
0078 EXPORT_SYMBOL(pxa2xx_pcm_prepare);
0079 
0080 int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
0081 {
0082     struct snd_soc_pcm_runtime *rtd = substream->private_data;
0083     struct snd_pcm_runtime *runtime = substream->runtime;
0084     struct snd_dmaengine_dai_dma_data *dma_params;
0085     int ret;
0086 
0087     runtime->hw = pxa2xx_pcm_hardware;
0088 
0089     dma_params = snd_soc_dai_get_dma_data(asoc_rtd_to_cpu(rtd, 0), substream);
0090     if (!dma_params)
0091         return 0;
0092 
0093     /*
0094      * For mysterious reasons (and despite what the manual says)
0095      * playback samples are lost if the DMA count is not a multiple
0096      * of the DMA burst size.  Let's add a rule to enforce that.
0097      */
0098     ret = snd_pcm_hw_constraint_step(runtime, 0,
0099         SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
0100     if (ret)
0101         return ret;
0102 
0103     ret = snd_pcm_hw_constraint_step(runtime, 0,
0104         SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
0105     if (ret)
0106         return ret;
0107 
0108     ret = snd_pcm_hw_constraint_integer(runtime,
0109                         SNDRV_PCM_HW_PARAM_PERIODS);
0110     if (ret < 0)
0111         return ret;
0112 
0113     return snd_dmaengine_pcm_open(
0114         substream, dma_request_slave_channel(asoc_rtd_to_cpu(rtd, 0)->dev,
0115                              dma_params->chan_name));
0116 }
0117 EXPORT_SYMBOL(pxa2xx_pcm_open);
0118 
0119 int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
0120 {
0121     return snd_dmaengine_pcm_close_release_chan(substream);
0122 }
0123 EXPORT_SYMBOL(pxa2xx_pcm_close);
0124 
0125 int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm)
0126 {
0127     size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
0128 
0129     return snd_pcm_set_fixed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV_WC,
0130                         pcm->card->dev, size);
0131 }
0132 EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
0133 
0134 int pxa2xx_soc_pcm_new(struct snd_soc_component *component,
0135                struct snd_soc_pcm_runtime *rtd)
0136 {
0137     struct snd_card *card = rtd->card->snd_card;
0138     struct snd_pcm *pcm = rtd->pcm;
0139     int ret;
0140 
0141     ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
0142     if (ret)
0143         return ret;
0144 
0145     return pxa2xx_pcm_preallocate_dma_buffer(pcm);
0146 }
0147 EXPORT_SYMBOL(pxa2xx_soc_pcm_new);
0148 
0149 int pxa2xx_soc_pcm_open(struct snd_soc_component *component,
0150             struct snd_pcm_substream *substream)
0151 {
0152     return pxa2xx_pcm_open(substream);
0153 }
0154 EXPORT_SYMBOL(pxa2xx_soc_pcm_open);
0155 
0156 int pxa2xx_soc_pcm_close(struct snd_soc_component *component,
0157              struct snd_pcm_substream *substream)
0158 {
0159     return pxa2xx_pcm_close(substream);
0160 }
0161 EXPORT_SYMBOL(pxa2xx_soc_pcm_close);
0162 
0163 int pxa2xx_soc_pcm_hw_params(struct snd_soc_component *component,
0164                  struct snd_pcm_substream *substream,
0165                  struct snd_pcm_hw_params *params)
0166 {
0167     return pxa2xx_pcm_hw_params(substream, params);
0168 }
0169 EXPORT_SYMBOL(pxa2xx_soc_pcm_hw_params);
0170 
0171 int pxa2xx_soc_pcm_prepare(struct snd_soc_component *component,
0172                struct snd_pcm_substream *substream)
0173 {
0174     return pxa2xx_pcm_prepare(substream);
0175 }
0176 EXPORT_SYMBOL(pxa2xx_soc_pcm_prepare);
0177 
0178 int pxa2xx_soc_pcm_trigger(struct snd_soc_component *component,
0179                struct snd_pcm_substream *substream, int cmd)
0180 {
0181     return pxa2xx_pcm_trigger(substream, cmd);
0182 }
0183 EXPORT_SYMBOL(pxa2xx_soc_pcm_trigger);
0184 
0185 snd_pcm_uframes_t
0186 pxa2xx_soc_pcm_pointer(struct snd_soc_component *component,
0187                struct snd_pcm_substream *substream)
0188 {
0189     return pxa2xx_pcm_pointer(substream);
0190 }
0191 EXPORT_SYMBOL(pxa2xx_soc_pcm_pointer);
0192 
0193 MODULE_AUTHOR("Nicolas Pitre");
0194 MODULE_DESCRIPTION("Intel PXA2xx sound library");
0195 MODULE_LICENSE("GPL");