0001
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
0095
0096
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");