~hui.wang/alsa-driver/tiwai-trunk-fgit

« back to all changes in this revision

Viewing changes to arm/pxa2xx-pcm-lib.c

  • Committer: Hui Wang
  • Date: 2018-06-07 01:04:04 UTC
  • Revision ID: git-v1:baf13208df10376d9e4588ad3524aeb3c9973bdf
sync the alsa hda driver from Takashi's tree

Signed-off-by: Hui Wang <hui.wang@canonical.com>

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * This program is free software; you can redistribute it and/or modify
 
3
 * it under the terms of the GNU General Public License version 2 as
 
4
 * published by the Free Software Foundation.
 
5
 */
 
6
 
 
7
#include <linux/slab.h>
 
8
#include <linux/module.h>
 
9
#include <linux/dma-mapping.h>
 
10
#include <linux/dmaengine.h>
 
11
#include <linux/dma/pxa-dma.h>
 
12
 
 
13
#include <sound/core.h>
 
14
#include <sound/pcm.h>
 
15
#include <sound/pcm_params.h>
 
16
#include <sound/pxa2xx-lib.h>
 
17
#include <sound/dmaengine_pcm.h>
 
18
 
 
19
#include "pxa2xx-pcm.h"
 
20
 
 
21
static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
 
22
        .info                   = SNDRV_PCM_INFO_MMAP |
 
23
                                  SNDRV_PCM_INFO_MMAP_VALID |
 
24
                                  SNDRV_PCM_INFO_INTERLEAVED |
 
25
                                  SNDRV_PCM_INFO_PAUSE |
 
26
                                  SNDRV_PCM_INFO_RESUME,
 
27
        .formats                = SNDRV_PCM_FMTBIT_S16_LE |
 
28
                                        SNDRV_PCM_FMTBIT_S24_LE |
 
29
                                        SNDRV_PCM_FMTBIT_S32_LE,
 
30
        .period_bytes_min       = 32,
 
31
        .period_bytes_max       = 8192 - 32,
 
32
        .periods_min            = 1,
 
33
        .periods_max            = 256,
 
34
        .buffer_bytes_max       = 128 * 1024,
 
35
        .fifo_size              = 32,
 
36
};
 
37
 
 
38
int __pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
 
39
                                struct snd_pcm_hw_params *params)
 
40
{
 
41
        struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
 
42
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
43
        struct snd_dmaengine_dai_dma_data *dma_params;
 
44
        struct dma_slave_config config;
 
45
        int ret;
 
46
 
 
47
        dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
48
        if (!dma_params)
 
49
                return 0;
 
50
 
 
51
        ret = snd_hwparams_to_dma_slave_config(substream, params, &config);
 
52
        if (ret)
 
53
                return ret;
 
54
 
 
55
        snd_dmaengine_pcm_set_config_from_dai_data(substream,
 
56
                        snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
 
57
                        &config);
 
58
 
 
59
        ret = dmaengine_slave_config(chan, &config);
 
60
        if (ret)
 
61
                return ret;
 
62
 
 
63
        snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
 
64
 
 
65
        return 0;
 
66
}
 
67
EXPORT_SYMBOL(__pxa2xx_pcm_hw_params);
 
68
 
 
69
int __pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
 
70
{
 
71
        snd_pcm_set_runtime_buffer(substream, NULL);
 
72
        return 0;
 
73
}
 
74
EXPORT_SYMBOL(__pxa2xx_pcm_hw_free);
 
75
 
 
76
int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
77
{
 
78
        return snd_dmaengine_pcm_trigger(substream, cmd);
 
79
}
 
80
EXPORT_SYMBOL(pxa2xx_pcm_trigger);
 
81
 
 
82
snd_pcm_uframes_t
 
83
pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
 
84
{
 
85
        return snd_dmaengine_pcm_pointer(substream);
 
86
}
 
87
EXPORT_SYMBOL(pxa2xx_pcm_pointer);
 
88
 
 
89
int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
 
90
{
 
91
        return 0;
 
92
}
 
93
EXPORT_SYMBOL(__pxa2xx_pcm_prepare);
 
94
 
 
95
int __pxa2xx_pcm_open(struct snd_pcm_substream *substream)
 
96
{
 
97
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
 
98
        struct snd_pcm_runtime *runtime = substream->runtime;
 
99
        struct snd_dmaengine_dai_dma_data *dma_params;
 
100
        int ret;
 
101
 
 
102
        runtime->hw = pxa2xx_pcm_hardware;
 
103
 
 
104
        dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
 
105
        if (!dma_params)
 
106
                return 0;
 
107
 
 
108
        /*
 
109
         * For mysterious reasons (and despite what the manual says)
 
110
         * playback samples are lost if the DMA count is not a multiple
 
111
         * of the DMA burst size.  Let's add a rule to enforce that.
 
112
         */
 
113
        ret = snd_pcm_hw_constraint_step(runtime, 0,
 
114
                SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
 
115
        if (ret)
 
116
                return ret;
 
117
 
 
118
        ret = snd_pcm_hw_constraint_step(runtime, 0,
 
119
                SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
 
120
        if (ret)
 
121
                return ret;
 
122
 
 
123
        ret = snd_pcm_hw_constraint_integer(runtime,
 
124
                                            SNDRV_PCM_HW_PARAM_PERIODS);
 
125
        if (ret < 0)
 
126
                return ret;
 
127
 
 
128
        return snd_dmaengine_pcm_open_request_chan(substream,
 
129
                                        pxad_filter_fn,
 
130
                                        dma_params->filter_data);
 
131
}
 
132
EXPORT_SYMBOL(__pxa2xx_pcm_open);
 
133
 
 
134
int __pxa2xx_pcm_close(struct snd_pcm_substream *substream)
 
135
{
 
136
        return snd_dmaengine_pcm_close_release_chan(substream);
 
137
}
 
138
EXPORT_SYMBOL(__pxa2xx_pcm_close);
 
139
 
 
140
int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
 
141
        struct vm_area_struct *vma)
 
142
{
 
143
        struct snd_pcm_runtime *runtime = substream->runtime;
 
144
        return dma_mmap_wc(substream->pcm->card->dev, vma, runtime->dma_area,
 
145
                           runtime->dma_addr, runtime->dma_bytes);
 
146
}
 
147
EXPORT_SYMBOL(pxa2xx_pcm_mmap);
 
148
 
 
149
int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
 
150
{
 
151
        struct snd_pcm_substream *substream = pcm->streams[stream].substream;
 
152
        struct snd_dma_buffer *buf = &substream->dma_buffer;
 
153
        size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
 
154
        buf->dev.type = SNDRV_DMA_TYPE_DEV;
 
155
        buf->dev.dev = pcm->card->dev;
 
156
        buf->private_data = NULL;
 
157
        buf->area = dma_alloc_wc(pcm->card->dev, size, &buf->addr, GFP_KERNEL);
 
158
        if (!buf->area)
 
159
                return -ENOMEM;
 
160
        buf->bytes = size;
 
161
        return 0;
 
162
}
 
163
EXPORT_SYMBOL(pxa2xx_pcm_preallocate_dma_buffer);
 
164
 
 
165
void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
 
166
{
 
167
        struct snd_pcm_substream *substream;
 
168
        struct snd_dma_buffer *buf;
 
169
        int stream;
 
170
 
 
171
        for (stream = 0; stream < 2; stream++) {
 
172
                substream = pcm->streams[stream].substream;
 
173
                if (!substream)
 
174
                        continue;
 
175
                buf = &substream->dma_buffer;
 
176
                if (!buf->area)
 
177
                        continue;
 
178
                dma_free_wc(pcm->card->dev, buf->bytes, buf->area, buf->addr);
 
179
                buf->area = NULL;
 
180
        }
 
181
}
 
182
EXPORT_SYMBOL(pxa2xx_pcm_free_dma_buffers);
 
183
 
 
184
MODULE_AUTHOR("Nicolas Pitre");
 
185
MODULE_DESCRIPTION("Intel PXA2xx sound library");
 
186
MODULE_LICENSE("GPL");