aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/blackfin
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2013-05-28 13:22:17 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-05-30 07:33:41 -0400
commitcc37961b21eb3d57d421ca34ffec9bbe0a6096c0 (patch)
tree3a10e59aae5e9788b8920e9acaafbfe7cb3f8223 /sound/soc/blackfin
parent34f4095564ff334adae5ab4a9904f8d66d03e994 (diff)
ASoC: blackfin: Remove bf5xx-tdm driver
Now that the bf5xx-i2s driver supports TDM mode and all users of the bf5xx-tdm driver have been switch over to using the bf5xx-i2s driver there is no need to keep the b5fxx-tdm driver around. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/blackfin')
-rw-r--r--sound/soc/blackfin/Kconfig13
-rw-r--r--sound/soc/blackfin/Makefile4
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c343
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c328
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h23
5 files changed, 0 insertions, 711 deletions
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 4a67865bc4fc..54f74f8cbb75 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -89,16 +89,6 @@ config SND_BFIN_AD73311_SE
89 Enter the GPIO used to control AD73311's SE pin. Acceptable 89 Enter the GPIO used to control AD73311's SE pin. Acceptable
90 values are 0 to 7 90 values are 0 to 7
91 91
92config SND_BF5XX_TDM
93 tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
94 depends on (BLACKFIN && SND_SOC)
95 select SND_BF5XX_SOC_SPORT
96 help
97 Say Y or M if you want to add support for codecs attached to
98 the Blackfin SPORT (synchronous serial ports) interface in TDM
99 mode.
100 You will also need to select the audio interfaces to support below.
101
102config SND_BF5XX_AC97 92config SND_BF5XX_AC97
103 tristate "SoC AC97 Audio for the ADI BF5xx chip" 93 tristate "SoC AC97 Audio for the ADI BF5xx chip"
104 depends on BLACKFIN 94 depends on BLACKFIN
@@ -174,9 +164,6 @@ config SND_BF5XX_SOC_I2S
174config SND_BF6XX_SOC_I2S 164config SND_BF6XX_SOC_I2S
175 tristate 165 tristate
176 166
177config SND_BF5XX_SOC_TDM
178 tristate
179
180config SND_BF5XX_SOC_AC97 167config SND_BF5XX_SOC_AC97
181 tristate 168 tristate
182 169
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile
index 6fea1f4cbee2..ad0a6e99bc5d 100644
--- a/sound/soc/blackfin/Makefile
+++ b/sound/soc/blackfin/Makefile
@@ -1,23 +1,19 @@
1# Blackfin Platform Support 1# Blackfin Platform Support
2snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o 2snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o
3snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o 3snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o
4snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o
5snd-soc-bf5xx-sport-objs := bf5xx-sport.o 4snd-soc-bf5xx-sport-objs := bf5xx-sport.o
6snd-soc-bf6xx-sport-objs := bf6xx-sport.o 5snd-soc-bf6xx-sport-objs := bf6xx-sport.o
7snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o 6snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o
8snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o 7snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o
9snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o 8snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o
10snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o
11 9
12obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o 10obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o
13obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o 11obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o
14obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o
15obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o 12obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o
16obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o 13obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o
17obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o 14obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o
18obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o 15obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o
19obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o 16obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o
20obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o
21 17
22# Blackfin Machine Support 18# Blackfin Machine Support
23snd-ad1836-objs := bf5xx-ad1836.o 19snd-ad1836-objs := bf5xx-ad1836.o
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
deleted file mode 100644
index a6b5457036ef..000000000000
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ /dev/null
@@ -1,343 +0,0 @@
1/*
2 * File: sound/soc/blackfin/bf5xx-tdm-pcm.c
3 * Author: Barry Song <Barry.Song@analog.com>
4 *
5 * Created: Tue June 06 2009
6 * Description: DMA driver for tdm codec
7 *
8 * Modified:
9 * Copyright 2009 Analog Devices Inc.
10 *
11 * Bugs: Enter bugs at http://blackfin.uclinux.org/
12 *
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, see the file COPYING, or write
25 * to the Free Software Foundation, Inc.,
26 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 */
28
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/platform_device.h>
32#include <linux/dma-mapping.h>
33#include <linux/gfp.h>
34
35#include <sound/core.h>
36#include <sound/pcm.h>
37#include <sound/pcm_params.h>
38#include <sound/soc.h>
39
40#include <asm/dma.h>
41
42#include "bf5xx-tdm.h"
43#include "bf5xx-sport.h"
44
45#define PCM_BUFFER_MAX 0x8000
46#define FRAGMENT_SIZE_MIN (4*1024)
47#define FRAGMENTS_MIN 2
48#define FRAGMENTS_MAX 32
49
50static void bf5xx_dma_irq(void *data)
51{
52 struct snd_pcm_substream *pcm = data;
53 snd_pcm_period_elapsed(pcm);
54}
55
56static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
57 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
58 SNDRV_PCM_INFO_RESUME),
59 .formats = SNDRV_PCM_FMTBIT_S32_LE,
60 .rates = SNDRV_PCM_RATE_48000,
61 .channels_min = 2,
62 .channels_max = 8,
63 .buffer_bytes_max = PCM_BUFFER_MAX,
64 .period_bytes_min = FRAGMENT_SIZE_MIN,
65 .period_bytes_max = PCM_BUFFER_MAX/2,
66 .periods_min = FRAGMENTS_MIN,
67 .periods_max = FRAGMENTS_MAX,
68};
69
70static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
71 struct snd_pcm_hw_params *params)
72{
73 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
74 snd_pcm_lib_malloc_pages(substream, size * 4);
75
76 return 0;
77}
78
79static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
80{
81 snd_pcm_lib_free_pages(substream);
82
83 return 0;
84}
85
86static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
87{
88 struct snd_pcm_runtime *runtime = substream->runtime;
89 struct sport_device *sport = runtime->private_data;
90 int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size);
91
92 fragsize_bytes /= runtime->channels;
93 /* inflate the fragsize to match the dma width of SPORT */
94 fragsize_bytes *= 8;
95
96 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
97 sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
98 sport_config_tx_dma(sport, runtime->dma_area,
99 runtime->periods, fragsize_bytes);
100 } else {
101 sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
102 sport_config_rx_dma(sport, runtime->dma_area,
103 runtime->periods, fragsize_bytes);
104 }
105
106 return 0;
107}
108
109static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
110{
111 struct snd_pcm_runtime *runtime = substream->runtime;
112 struct sport_device *sport = runtime->private_data;
113 int ret = 0;
114
115 switch (cmd) {
116 case SNDRV_PCM_TRIGGER_START:
117 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
118 sport_tx_start(sport);
119 else
120 sport_rx_start(sport);
121 break;
122 case SNDRV_PCM_TRIGGER_STOP:
123 case SNDRV_PCM_TRIGGER_SUSPEND:
124 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
125 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
126 sport_tx_stop(sport);
127 else
128 sport_rx_stop(sport);
129 break;
130 default:
131 ret = -EINVAL;
132 }
133
134 return ret;
135}
136
137static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
138{
139 struct snd_pcm_runtime *runtime = substream->runtime;
140 struct sport_device *sport = runtime->private_data;
141 unsigned int diff;
142 snd_pcm_uframes_t frames;
143
144 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
145 diff = sport_curr_offset_tx(sport);
146 frames = diff / (8*4); /* 32 bytes per frame */
147 } else {
148 diff = sport_curr_offset_rx(sport);
149 frames = diff / (8*4);
150 }
151 return frames;
152}
153
154static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
155{
156 struct snd_soc_pcm_runtime *rtd = substream->private_data;
157 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
158 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
159 struct snd_pcm_runtime *runtime = substream->runtime;
160 struct snd_dma_buffer *buf = &substream->dma_buffer;
161
162 int ret = 0;
163
164 snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
165
166 ret = snd_pcm_hw_constraint_integer(runtime,
167 SNDRV_PCM_HW_PARAM_PERIODS);
168 if (ret < 0)
169 goto out;
170
171 if (sport_handle != NULL) {
172 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
173 sport_handle->tx_buf = buf->area;
174 else
175 sport_handle->rx_buf = buf->area;
176
177 runtime->private_data = sport_handle;
178 } else {
179 pr_err("sport_handle is NULL\n");
180 ret = -ENODEV;
181 }
182out:
183 return ret;
184}
185
186static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
187 snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
188{
189 struct snd_pcm_runtime *runtime = substream->runtime;
190 struct sport_device *sport = runtime->private_data;
191 struct bf5xx_tdm_port *tdm_port = sport->private_data;
192 unsigned int *src;
193 unsigned int *dst;
194 int i;
195
196 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
197 src = buf;
198 dst = (unsigned int *)substream->runtime->dma_area;
199
200 dst += pos * 8;
201 while (count--) {
202 for (i = 0; i < substream->runtime->channels; i++)
203 *(dst + tdm_port->tx_map[i]) = *src++;
204 dst += 8;
205 }
206 } else {
207 src = (unsigned int *)substream->runtime->dma_area;
208 dst = buf;
209
210 src += pos * 8;
211 while (count--) {
212 for (i = 0; i < substream->runtime->channels; i++)
213 *dst++ = *(src + tdm_port->rx_map[i]);
214 src += 8;
215 }
216 }
217
218 return 0;
219}
220
221static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
222 int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
223{
224 unsigned char *buf = substream->runtime->dma_area;
225 buf += pos * 8 * 4;
226 memset(buf, '\0', count * 8 * 4);
227
228 return 0;
229}
230
231static struct snd_pcm_ops bf5xx_pcm_tdm_ops = {
232 .open = bf5xx_pcm_open,
233 .ioctl = snd_pcm_lib_ioctl,
234 .hw_params = bf5xx_pcm_hw_params,
235 .hw_free = bf5xx_pcm_hw_free,
236 .prepare = bf5xx_pcm_prepare,
237 .trigger = bf5xx_pcm_trigger,
238 .pointer = bf5xx_pcm_pointer,
239 .copy = bf5xx_pcm_copy,
240 .silence = bf5xx_pcm_silence,
241};
242
243static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
244{
245 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
246 struct snd_dma_buffer *buf = &substream->dma_buffer;
247 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
248
249 buf->dev.type = SNDRV_DMA_TYPE_DEV;
250 buf->dev.dev = pcm->card->dev;
251 buf->private_data = NULL;
252 buf->area = dma_alloc_coherent(pcm->card->dev, size * 4,
253 &buf->addr, GFP_KERNEL);
254 if (!buf->area) {
255 pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
256 return -ENOMEM;
257 }
258 buf->bytes = size;
259
260 return 0;
261}
262
263static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
264{
265 struct snd_pcm_substream *substream;
266 struct snd_dma_buffer *buf;
267 int stream;
268
269 for (stream = 0; stream < 2; stream++) {
270 substream = pcm->streams[stream].substream;
271 if (!substream)
272 continue;
273
274 buf = &substream->dma_buffer;
275 if (!buf->area)
276 continue;
277 dma_free_coherent(NULL, buf->bytes, buf->area, 0);
278 buf->area = NULL;
279 }
280}
281
282static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
283
284static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
285{
286 struct snd_card *card = rtd->card->snd_card;
287 struct snd_pcm *pcm = rtd->pcm;
288 int ret = 0;
289
290 if (!card->dev->dma_mask)
291 card->dev->dma_mask = &bf5xx_pcm_dmamask;
292 if (!card->dev->coherent_dma_mask)
293 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
294
295 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
296 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
297 SNDRV_PCM_STREAM_PLAYBACK);
298 if (ret)
299 goto out;
300 }
301
302 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
303 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
304 SNDRV_PCM_STREAM_CAPTURE);
305 if (ret)
306 goto out;
307 }
308out:
309 return ret;
310}
311
312static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
313 .ops = &bf5xx_pcm_tdm_ops,
314 .pcm_new = bf5xx_pcm_tdm_new,
315 .pcm_free = bf5xx_pcm_free_dma_buffers,
316};
317
318static int bf5xx_soc_platform_probe(struct platform_device *pdev)
319{
320 return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
321}
322
323static int bf5xx_soc_platform_remove(struct platform_device *pdev)
324{
325 snd_soc_unregister_platform(&pdev->dev);
326 return 0;
327}
328
329static struct platform_driver bfin_tdm_driver = {
330 .driver = {
331 .name = "bfin-tdm-pcm-audio",
332 .owner = THIS_MODULE,
333 },
334
335 .probe = bf5xx_soc_platform_probe,
336 .remove = bf5xx_soc_platform_remove,
337};
338
339module_platform_driver(bfin_tdm_driver);
340
341MODULE_AUTHOR("Barry Song");
342MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
343MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
deleted file mode 100644
index aa0851650b56..000000000000
--- a/sound/soc/blackfin/bf5xx-tdm.c
+++ /dev/null
@@ -1,328 +0,0 @@
1/*
2 * File: sound/soc/blackfin/bf5xx-tdm.c
3 * Author: Barry Song <Barry.Song@analog.com>
4 *
5 * Created: Thurs June 04 2009
6 * Description: Blackfin I2S(TDM) CPU DAI driver
7 * Even though TDM mode can be as part of I2S DAI, but there
8 * are so much difference in configuration and data flow,
9 * it's very ugly to integrate I2S and TDM into a module
10 *
11 * Modified:
12 * Copyright 2009 Analog Devices Inc.
13 *
14 * Bugs: Enter bugs at http://blackfin.uclinux.org/
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see the file COPYING, or write
28 * to the Free Software Foundation, Inc.,
29 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32#include <linux/init.h>
33#include <linux/module.h>
34#include <linux/device.h>
35#include <sound/core.h>
36#include <sound/pcm.h>
37#include <sound/pcm_params.h>
38#include <sound/initval.h>
39#include <sound/soc.h>
40
41#include <asm/irq.h>
42#include <asm/portmux.h>
43#include <linux/mutex.h>
44#include <linux/gpio.h>
45
46#include "bf5xx-sport.h"
47#include "bf5xx-tdm.h"
48
49static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai,
50 unsigned int fmt)
51{
52 int ret = 0;
53
54 /* interface format:support TDM,slave mode */
55 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
56 case SND_SOC_DAIFMT_DSP_A:
57 break;
58 default:
59 printk(KERN_ERR "%s: Unknown DAI format type\n", __func__);
60 ret = -EINVAL;
61 break;
62 }
63
64 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
65 case SND_SOC_DAIFMT_CBM_CFM:
66 break;
67 case SND_SOC_DAIFMT_CBS_CFS:
68 case SND_SOC_DAIFMT_CBM_CFS:
69 case SND_SOC_DAIFMT_CBS_CFM:
70 ret = -EINVAL;
71 break;
72 default:
73 printk(KERN_ERR "%s: Unknown DAI master type\n", __func__);
74 ret = -EINVAL;
75 break;
76 }
77
78 return ret;
79}
80
81static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream,
82 struct snd_pcm_hw_params *params,
83 struct snd_soc_dai *dai)
84{
85 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
86 struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
87 int ret = 0;
88
89 bf5xx_tdm->tcr2 &= ~0x1f;
90 bf5xx_tdm->rcr2 &= ~0x1f;
91 switch (params_format(params)) {
92 case SNDRV_PCM_FORMAT_S32_LE:
93 bf5xx_tdm->tcr2 |= 31;
94 bf5xx_tdm->rcr2 |= 31;
95 sport_handle->wdsize = 4;
96 break;
97 /* at present, we only support 32bit transfer */
98 default:
99 pr_err("not supported PCM format yet\n");
100 return -EINVAL;
101 break;
102 }
103
104 if (!bf5xx_tdm->configured) {
105 /*
106 * TX and RX are not independent,they are enabled at the
107 * same time, even if only one side is running. So, we
108 * need to configure both of them at the time when the first
109 * stream is opened.
110 *
111 * CPU DAI:slave mode.
112 */
113 ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1,
114 bf5xx_tdm->rcr2, 0, 0);
115 if (ret) {
116 pr_err("SPORT is busy!\n");
117 return -EBUSY;
118 }
119
120 ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1,
121 bf5xx_tdm->tcr2, 0, 0);
122 if (ret) {
123 pr_err("SPORT is busy!\n");
124 return -EBUSY;
125 }
126
127 bf5xx_tdm->configured = 1;
128 }
129
130 return 0;
131}
132
133static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream,
134 struct snd_soc_dai *dai)
135{
136 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
137 struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
138
139 /* No active stream, SPORT is allowed to be configured again. */
140 if (!dai->active)
141 bf5xx_tdm->configured = 0;
142}
143
144static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai,
145 unsigned int tx_num, unsigned int *tx_slot,
146 unsigned int rx_num, unsigned int *rx_slot)
147{
148 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
149 struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data;
150 int i;
151 unsigned int slot;
152 unsigned int tx_mapped = 0, rx_mapped = 0;
153
154 if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
155 (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
156 return -EINVAL;
157
158 for (i = 0; i < tx_num; i++) {
159 slot = tx_slot[i];
160 if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
161 (!(tx_mapped & (1 << slot)))) {
162 bf5xx_tdm->tx_map[i] = slot;
163 tx_mapped |= 1 << slot;
164 } else
165 return -EINVAL;
166 }
167 for (i = 0; i < rx_num; i++) {
168 slot = rx_slot[i];
169 if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
170 (!(rx_mapped & (1 << slot)))) {
171 bf5xx_tdm->rx_map[i] = slot;
172 rx_mapped |= 1 << slot;
173 } else
174 return -EINVAL;
175 }
176
177 return 0;
178}
179
180#ifdef CONFIG_PM
181static int bf5xx_tdm_suspend(struct snd_soc_dai *dai)
182{
183 struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
184
185 if (dai->playback_active)
186 sport_tx_stop(sport);
187 if (dai->capture_active)
188 sport_rx_stop(sport);
189
190 /* isolate sync/clock pins from codec while sports resume */
191 peripheral_free_list(sport->pin_req);
192
193 return 0;
194}
195
196static int bf5xx_tdm_resume(struct snd_soc_dai *dai)
197{
198 int ret;
199 struct sport_device *sport = snd_soc_dai_get_drvdata(dai);
200
201 ret = sport_set_multichannel(sport, 8, 0xFF, 0xFF, 1);
202 if (ret) {
203 pr_err("SPORT is busy!\n");
204 ret = -EBUSY;
205 }
206
207 ret = sport_config_rx(sport, 0, 0x1F, 0, 0);
208 if (ret) {
209 pr_err("SPORT is busy!\n");
210 ret = -EBUSY;
211 }
212
213 ret = sport_config_tx(sport, 0, 0x1F, 0, 0);
214 if (ret) {
215 pr_err("SPORT is busy!\n");
216 ret = -EBUSY;
217 }
218
219 peripheral_request_list(sport->pin_req, "soc-audio");
220
221 return 0;
222}
223
224#else
225#define bf5xx_tdm_suspend NULL
226#define bf5xx_tdm_resume NULL
227#endif
228
229static const struct snd_soc_dai_ops bf5xx_tdm_dai_ops = {
230 .hw_params = bf5xx_tdm_hw_params,
231 .set_fmt = bf5xx_tdm_set_dai_fmt,
232 .shutdown = bf5xx_tdm_shutdown,
233 .set_channel_map = bf5xx_tdm_set_channel_map,
234};
235
236static struct snd_soc_dai_driver bf5xx_tdm_dai = {
237 .suspend = bf5xx_tdm_suspend,
238 .resume = bf5xx_tdm_resume,
239 .playback = {
240 .channels_min = 2,
241 .channels_max = 8,
242 .rates = SNDRV_PCM_RATE_48000,
243 .formats = SNDRV_PCM_FMTBIT_S32_LE,},
244 .capture = {
245 .channels_min = 2,
246 .channels_max = 8,
247 .rates = SNDRV_PCM_RATE_48000,
248 .formats = SNDRV_PCM_FMTBIT_S32_LE,},
249 .ops = &bf5xx_tdm_dai_ops,
250};
251
252static const struct snd_soc_component_driver bf5xx_tdm_component = {
253 .name = "bf5xx-tdm",
254};
255
256static int bfin_tdm_probe(struct platform_device *pdev)
257{
258 struct sport_device *sport_handle;
259 int ret;
260
261 /* configure SPORT for TDM */
262 sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
263 sizeof(struct bf5xx_tdm_port));
264 if (!sport_handle)
265 return -ENODEV;
266
267 /* SPORT works in TDM mode */
268 ret = sport_set_multichannel(sport_handle, 8, 0xFF, 0xFF, 1);
269 if (ret) {
270 pr_err("SPORT is busy!\n");
271 ret = -EBUSY;
272 goto sport_config_err;
273 }
274
275 ret = sport_config_rx(sport_handle, 0, 0x1F, 0, 0);
276 if (ret) {
277 pr_err("SPORT is busy!\n");
278 ret = -EBUSY;
279 goto sport_config_err;
280 }
281
282 ret = sport_config_tx(sport_handle, 0, 0x1F, 0, 0);
283 if (ret) {
284 pr_err("SPORT is busy!\n");
285 ret = -EBUSY;
286 goto sport_config_err;
287 }
288
289 ret = snd_soc_register_component(&pdev->dev, &bf5xx_tdm_component,
290 &bf5xx_tdm_dai, 1);
291 if (ret) {
292 pr_err("Failed to register DAI: %d\n", ret);
293 goto sport_config_err;
294 }
295
296 return 0;
297
298sport_config_err:
299 sport_done(sport_handle);
300 return ret;
301}
302
303static int bfin_tdm_remove(struct platform_device *pdev)
304{
305 struct sport_device *sport_handle = platform_get_drvdata(pdev);
306
307 snd_soc_unregister_component(&pdev->dev);
308 sport_done(sport_handle);
309
310 return 0;
311}
312
313static struct platform_driver bfin_tdm_driver = {
314 .probe = bfin_tdm_probe,
315 .remove = bfin_tdm_remove,
316 .driver = {
317 .name = "bfin-tdm",
318 .owner = THIS_MODULE,
319 },
320};
321
322module_platform_driver(bfin_tdm_driver);
323
324/* Module information */
325MODULE_AUTHOR("Barry Song");
326MODULE_DESCRIPTION("TDM driver for ADI Blackfin");
327MODULE_LICENSE("GPL");
328
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h
deleted file mode 100644
index e986a3ea3315..000000000000
--- a/sound/soc/blackfin/bf5xx-tdm.h
+++ /dev/null
@@ -1,23 +0,0 @@
1/*
2 * sound/soc/blackfin/bf5xx-tdm.h
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#ifndef _BF5XX_TDM_H
10#define _BF5XX_TDM_H
11
12#define BFIN_TDM_DAI_MAX_SLOTS 8
13struct bf5xx_tdm_port {
14 u16 tcr1;
15 u16 rcr1;
16 u16 tcr2;
17 u16 rcr2;
18 unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS];
19 unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS];
20 int configured;
21};
22
23#endif