aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/blackfin
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/blackfin')
-rw-r--r--sound/soc/blackfin/Kconfig47
-rw-r--r--sound/soc/blackfin/Makefile4
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.c1
-rw-r--r--sound/soc/blackfin/bf5xx-ac97-pcm.h26
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c37
-rw-r--r--sound/soc/blackfin/bf5xx-ad1836.c19
-rw-r--r--sound/soc/blackfin/bf5xx-ad193x.c40
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c1
-rw-r--r--sound/soc/blackfin/bf5xx-ad73311.c1
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.c183
-rw-r--r--sound/soc/blackfin/bf5xx-i2s-pcm.h21
-rw-r--r--sound/soc/blackfin/bf5xx-i2s.c129
-rw-r--r--sound/soc/blackfin/bf5xx-sport.c10
-rw-r--r--sound/soc/blackfin/bf5xx-sport.h2
-rw-r--r--sound/soc/blackfin/bf5xx-ssm2602.c1
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.c345
-rw-r--r--sound/soc/blackfin/bf5xx-tdm-pcm.h18
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c328
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.h23
19 files changed, 292 insertions, 944 deletions
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig
index 16b88f5c26e2..54f74f8cbb75 100644
--- a/sound/soc/blackfin/Kconfig
+++ b/sound/soc/blackfin/Kconfig
@@ -56,6 +56,23 @@ config SND_SOC_BFIN_EVAL_ADAV80X
56 Note: This driver assumes that the ADAV80X digital record and playback 56 Note: This driver assumes that the ADAV80X digital record and playback
57 interfaces are connected to the first SPORT port on the BF5XX board. 57 interfaces are connected to the first SPORT port on the BF5XX board.
58 58
59config SND_BF5XX_SOC_AD1836
60 tristate "SoC AD1836 Audio support for BF5xx"
61 depends on SND_BF5XX_I2S
62 select SND_BF5XX_SOC_I2S
63 select SND_SOC_AD1836
64 help
65 Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
66
67config SND_BF5XX_SOC_AD193X
68 tristate "SoC AD193X Audio support for Blackfin"
69 depends on SND_BF5XX_I2S
70 select SND_BF5XX_SOC_I2S
71 select SND_SOC_AD193X
72 help
73 Say Y if you want to add support for AD193X codec on Blackfin.
74 This driver supports AD1936, AD1937, AD1938 and AD1939.
75
59config SND_BF5XX_SOC_AD73311 76config SND_BF5XX_SOC_AD73311
60 tristate "SoC AD73311 Audio support for Blackfin" 77 tristate "SoC AD73311 Audio support for Blackfin"
61 depends on SND_BF5XX_I2S 78 depends on SND_BF5XX_I2S
@@ -72,33 +89,6 @@ config SND_BFIN_AD73311_SE
72 Enter the GPIO used to control AD73311's SE pin. Acceptable 89 Enter the GPIO used to control AD73311's SE pin. Acceptable
73 values are 0 to 7 90 values are 0 to 7
74 91
75config SND_BF5XX_TDM
76 tristate "SoC I2S(TDM mode) Audio for the ADI BF5xx chip"
77 depends on (BLACKFIN && SND_SOC)
78 select SND_BF5XX_SOC_SPORT
79 help
80 Say Y or M if you want to add support for codecs attached to
81 the Blackfin SPORT (synchronous serial ports) interface in TDM
82 mode.
83 You will also need to select the audio interfaces to support below.
84
85config SND_BF5XX_SOC_AD1836
86 tristate "SoC AD1836 Audio support for BF5xx"
87 depends on SND_BF5XX_TDM
88 select SND_BF5XX_SOC_TDM
89 select SND_SOC_AD1836
90 help
91 Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
92
93config SND_BF5XX_SOC_AD193X
94 tristate "SoC AD193X Audio support for Blackfin"
95 depends on SND_BF5XX_TDM
96 select SND_BF5XX_SOC_TDM
97 select SND_SOC_AD193X
98 help
99 Say Y if you want to add support for AD193X codec on Blackfin.
100 This driver supports AD1936, AD1937, AD1938 and AD1939.
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-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c
index 7e2f36004a5a..53f84085bf1f 100644
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.c
+++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c
@@ -39,7 +39,6 @@
39 39
40#include <asm/dma.h> 40#include <asm/dma.h>
41 41
42#include "bf5xx-ac97-pcm.h"
43#include "bf5xx-ac97.h" 42#include "bf5xx-ac97.h"
44#include "bf5xx-sport.h" 43#include "bf5xx-sport.h"
45 44
diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.h b/sound/soc/blackfin/bf5xx-ac97-pcm.h
deleted file mode 100644
index d324d5826a9b..000000000000
--- a/sound/soc/blackfin/bf5xx-ac97-pcm.h
+++ /dev/null
@@ -1,26 +0,0 @@
1/*
2 * linux/sound/arm/bf5xx-ac97-pcm.h -- ALSA PCM interface for the Blackfin
3 *
4 * Copyright 2007 Analog Device Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef _BF5XX_AC97_PCM_H
12#define _BF5XX_AC97_PCM_H
13
14struct bf5xx_pcm_dma_params {
15 char *name; /* stream identifier */
16};
17
18struct bf5xx_gpio {
19 u32 sys;
20 u32 rx;
21 u32 tx;
22 u32 clk;
23 u32 frm;
24};
25
26#endif
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index 490217325975..efb1daecd0dd 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -198,13 +198,12 @@ static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97)
198#endif 198#endif
199} 199}
200 200
201struct snd_ac97_bus_ops soc_ac97_ops = { 201static struct snd_ac97_bus_ops bf5xx_ac97_ops = {
202 .read = bf5xx_ac97_read, 202 .read = bf5xx_ac97_read,
203 .write = bf5xx_ac97_write, 203 .write = bf5xx_ac97_write,
204 .warm_reset = bf5xx_ac97_warm_reset, 204 .warm_reset = bf5xx_ac97_warm_reset,
205 .reset = bf5xx_ac97_cold_reset, 205 .reset = bf5xx_ac97_cold_reset,
206}; 206};
207EXPORT_SYMBOL_GPL(soc_ac97_ops);
208 207
209#ifdef CONFIG_PM 208#ifdef CONFIG_PM
210static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) 209static int bf5xx_ac97_suspend(struct snd_soc_dai *dai)
@@ -231,9 +230,9 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
231 return 0; 230 return 0;
232 231
233#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) 232#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
234 ret = sport_set_multichannel(sport, 16, 0x3FF, 1); 233 ret = sport_set_multichannel(sport, 16, 0x3FF, 0x3FF, 1);
235#else 234#else
236 ret = sport_set_multichannel(sport, 16, 0x1F, 1); 235 ret = sport_set_multichannel(sport, 16, 0x1F, 0x1F, 1);
237#endif 236#endif
238 if (ret) { 237 if (ret) {
239 pr_err("SPORT is busy!\n"); 238 pr_err("SPORT is busy!\n");
@@ -293,13 +292,14 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
293 292
294#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 293#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET
295 /* Request PB3 as reset pin */ 294 /* Request PB3 as reset pin */
296 if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { 295 ret = devm_gpio_request_one(&pdev->dev,
297 pr_err("Failed to request GPIO_%d for reset\n", 296 CONFIG_SND_BF5XX_RESET_GPIO_NUM,
298 CONFIG_SND_BF5XX_RESET_GPIO_NUM); 297 GPIOF_OUT_INIT_HIGH, "SND_AD198x RESET") {
299 ret = -1; 298 dev_err(&pdev->dev,
299 "Failed to request GPIO_%d for reset: %d\n",
300 CONFIG_SND_BF5XX_RESET_GPIO_NUM, ret);
300 goto gpio_err; 301 goto gpio_err;
301 } 302 }
302 gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1);
303#endif 303#endif
304 304
305 sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame), 305 sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame),
@@ -311,9 +311,9 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
311 311
312 /*SPORT works in TDM mode to simulate AC97 transfers*/ 312 /*SPORT works in TDM mode to simulate AC97 transfers*/
313#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) 313#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT)
314 ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1); 314 ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 0x3FF, 1);
315#else 315#else
316 ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); 316 ret = sport_set_multichannel(sport_handle, 16, 0x1F, 0x1F, 1);
317#endif 317#endif
318 if (ret) { 318 if (ret) {
319 pr_err("SPORT is busy!\n"); 319 pr_err("SPORT is busy!\n");
@@ -335,6 +335,12 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
335 goto sport_config_err; 335 goto sport_config_err;
336 } 336 }
337 337
338 ret = snd_soc_set_ac97_ops(&bf5xx_ac97_ops);
339 if (ret != 0) {
340 dev_err(&pdev->dev, "Failed to set AC'97 ops: %d\n", ret);
341 goto sport_config_err;
342 }
343
338 ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component, 344 ret = snd_soc_register_component(&pdev->dev, &bfin_ac97_component,
339 &bfin_ac97_dai, 1); 345 &bfin_ac97_dai, 1);
340 if (ret) { 346 if (ret) {
@@ -349,10 +355,7 @@ static int asoc_bfin_ac97_probe(struct platform_device *pdev)
349sport_config_err: 355sport_config_err:
350 sport_done(sport_handle); 356 sport_done(sport_handle);
351sport_err: 357sport_err:
352#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 358 snd_soc_set_ac97_ops(NULL);
353 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
354gpio_err:
355#endif
356 359
357 return ret; 360 return ret;
358} 361}
@@ -363,9 +366,7 @@ static int asoc_bfin_ac97_remove(struct platform_device *pdev)
363 366
364 snd_soc_unregister_component(&pdev->dev); 367 snd_soc_unregister_component(&pdev->dev);
365 sport_done(sport_handle); 368 sport_done(sport_handle);
366#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 369 snd_soc_set_ac97_ops(NULL);
367 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM);
368#endif
369 370
370 return 0; 371 return 0;
371} 372}
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c
index d23f4b0ea54f..8fcfc4ec3a51 100644
--- a/sound/soc/blackfin/bf5xx-ad1836.c
+++ b/sound/soc/blackfin/bf5xx-ad1836.c
@@ -30,15 +30,10 @@
30 30
31#include "../codecs/ad1836.h" 31#include "../codecs/ad1836.h"
32 32
33#include "bf5xx-tdm-pcm.h"
34#include "bf5xx-tdm.h"
35
36static struct snd_soc_card bf5xx_ad1836; 33static struct snd_soc_card bf5xx_ad1836;
37 34
38static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, 35static int bf5xx_ad1836_init(struct snd_soc_pcm_runtime *rtd)
39 struct snd_pcm_hw_params *params)
40{ 36{
41 struct snd_soc_pcm_runtime *rtd = substream->private_data;
42 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 37 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
43 unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7}; 38 unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7};
44 int ret = 0; 39 int ret = 0;
@@ -49,13 +44,13 @@ static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream,
49 if (ret < 0) 44 if (ret < 0)
50 return ret; 45 return ret;
51 46
47 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
48 if (ret < 0)
49 return ret;
50
52 return 0; 51 return 0;
53} 52}
54 53
55static struct snd_soc_ops bf5xx_ad1836_ops = {
56 .hw_params = bf5xx_ad1836_hw_params,
57};
58
59#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \ 54#define BF5XX_AD1836_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
60 SND_SOC_DAIFMT_CBM_CFM) 55 SND_SOC_DAIFMT_CBM_CFM)
61 56
@@ -63,9 +58,9 @@ static struct snd_soc_dai_link bf5xx_ad1836_dai = {
63 .name = "ad1836", 58 .name = "ad1836",
64 .stream_name = "AD1836", 59 .stream_name = "AD1836",
65 .codec_dai_name = "ad1836-hifi", 60 .codec_dai_name = "ad1836-hifi",
66 .platform_name = "bfin-tdm-pcm-audio", 61 .platform_name = "bfin-i2s-pcm-audio",
67 .ops = &bf5xx_ad1836_ops,
68 .dai_fmt = BF5XX_AD1836_DAIFMT, 62 .dai_fmt = BF5XX_AD1836_DAIFMT,
63 .init = bf5xx_ad1836_init,
69}; 64};
70 65
71static struct snd_soc_card bf5xx_ad1836 = { 66static struct snd_soc_card bf5xx_ad1836 = {
diff --git a/sound/soc/blackfin/bf5xx-ad193x.c b/sound/soc/blackfin/bf5xx-ad193x.c
index 0e55e9f2a514..603ad1f2b9b9 100644
--- a/sound/soc/blackfin/bf5xx-ad193x.c
+++ b/sound/soc/blackfin/bf5xx-ad193x.c
@@ -39,30 +39,16 @@
39 39
40#include "../codecs/ad193x.h" 40#include "../codecs/ad193x.h"
41 41
42#include "bf5xx-tdm-pcm.h"
43#include "bf5xx-tdm.h"
44
45static struct snd_soc_card bf5xx_ad193x; 42static struct snd_soc_card bf5xx_ad193x;
46 43
47static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, 44static int bf5xx_ad193x_link_init(struct snd_soc_pcm_runtime *rtd)
48 struct snd_pcm_hw_params *params)
49{ 45{
50 struct snd_soc_pcm_runtime *rtd = substream->private_data;
51 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 46 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
52 struct snd_soc_dai *codec_dai = rtd->codec_dai; 47 struct snd_soc_dai *codec_dai = rtd->codec_dai;
53 unsigned int clk = 0; 48 int ret;
54 unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7};
55 int ret = 0;
56
57 switch (params_rate(params)) {
58 case 48000:
59 clk = 24576000;
60 break;
61 }
62 49
63 /* set the codec system clock for DAC and ADC */ 50 /* set the codec system clock for DAC and ADC */
64 ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk, 51 ret = snd_soc_dai_set_sysclk(codec_dai, 0, 24576000, SND_SOC_CLOCK_IN);
65 SND_SOC_CLOCK_IN);
66 if (ret < 0) 52 if (ret < 0)
67 return ret; 53 return ret;
68 54
@@ -71,9 +57,7 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
71 if (ret < 0) 57 if (ret < 0)
72 return ret; 58 return ret;
73 59
74 /* set cpu DAI channel mapping */ 60 ret = snd_soc_dai_set_tdm_slot(cpu_dai, 0xFF, 0xFF, 8, 32);
75 ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map),
76 channel_map, ARRAY_SIZE(channel_map), channel_map);
77 if (ret < 0) 61 if (ret < 0)
78 return ret; 62 return ret;
79 63
@@ -83,30 +67,26 @@ static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
83#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \ 67#define BF5XX_AD193X_DAIFMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_IF | \
84 SND_SOC_DAIFMT_CBM_CFM) 68 SND_SOC_DAIFMT_CBM_CFM)
85 69
86static struct snd_soc_ops bf5xx_ad193x_ops = {
87 .hw_params = bf5xx_ad193x_hw_params,
88};
89
90static struct snd_soc_dai_link bf5xx_ad193x_dai[] = { 70static struct snd_soc_dai_link bf5xx_ad193x_dai[] = {
91 { 71 {
92 .name = "ad193x", 72 .name = "ad193x",
93 .stream_name = "AD193X", 73 .stream_name = "AD193X",
94 .cpu_dai_name = "bfin-tdm.0", 74 .cpu_dai_name = "bfin-i2s.0",
95 .codec_dai_name ="ad193x-hifi", 75 .codec_dai_name ="ad193x-hifi",
96 .platform_name = "bfin-tdm-pcm-audio", 76 .platform_name = "bfin-i2s-pcm-audio",
97 .codec_name = "spi0.5", 77 .codec_name = "spi0.5",
98 .ops = &bf5xx_ad193x_ops,
99 .dai_fmt = BF5XX_AD193X_DAIFMT, 78 .dai_fmt = BF5XX_AD193X_DAIFMT,
79 .init = bf5xx_ad193x_link_init,
100 }, 80 },
101 { 81 {
102 .name = "ad193x", 82 .name = "ad193x",
103 .stream_name = "AD193X", 83 .stream_name = "AD193X",
104 .cpu_dai_name = "bfin-tdm.1", 84 .cpu_dai_name = "bfin-i2s.1",
105 .codec_dai_name ="ad193x-hifi", 85 .codec_dai_name ="ad193x-hifi",
106 .platform_name = "bfin-tdm-pcm-audio", 86 .platform_name = "bfin-i2s-pcm-audio",
107 .codec_name = "spi0.5", 87 .codec_name = "spi0.5",
108 .ops = &bf5xx_ad193x_ops,
109 .dai_fmt = BF5XX_AD193X_DAIFMT, 88 .dai_fmt = BF5XX_AD193X_DAIFMT,
89 .init = bf5xx_ad193x_link_init,
110 }, 90 },
111}; 91};
112 92
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index b30f88bbd703..3450e8f9080d 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -48,7 +48,6 @@
48 48
49#include "../codecs/ad1980.h" 49#include "../codecs/ad1980.h"
50 50
51#include "bf5xx-ac97-pcm.h"
52#include "bf5xx-ac97.h" 51#include "bf5xx-ac97.h"
53 52
54static struct snd_soc_card bf5xx_board; 53static struct snd_soc_card bf5xx_board;
diff --git a/sound/soc/blackfin/bf5xx-ad73311.c b/sound/soc/blackfin/bf5xx-ad73311.c
index 61cc91d4a028..786bbdd96e7c 100644
--- a/sound/soc/blackfin/bf5xx-ad73311.c
+++ b/sound/soc/blackfin/bf5xx-ad73311.c
@@ -45,7 +45,6 @@
45 45
46#include "../codecs/ad73311.h" 46#include "../codecs/ad73311.h"
47#include "bf5xx-sport.h" 47#include "bf5xx-sport.h"
48#include "bf5xx-i2s-pcm.h"
49 48
50#if CONFIG_SND_BF5XX_SPORT_NUM == 0 49#if CONFIG_SND_BF5XX_SPORT_NUM == 0
51#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1 50#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c
index 262c1de364d8..9cb4a80df98e 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.c
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c
@@ -39,8 +39,8 @@
39 39
40#include <asm/dma.h> 40#include <asm/dma.h>
41 41
42#include "bf5xx-i2s-pcm.h"
43#include "bf5xx-sport.h" 42#include "bf5xx-sport.h"
43#include "bf5xx-i2s-pcm.h"
44 44
45static void bf5xx_dma_irq(void *data) 45static void bf5xx_dma_irq(void *data)
46{ 46{
@@ -50,7 +50,6 @@ static void bf5xx_dma_irq(void *data)
50 50
51static const struct snd_pcm_hardware bf5xx_pcm_hardware = { 51static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
52 .info = SNDRV_PCM_INFO_INTERLEAVED | 52 .info = SNDRV_PCM_INFO_INTERLEAVED |
53 SNDRV_PCM_INFO_MMAP |
54 SNDRV_PCM_INFO_MMAP_VALID | 53 SNDRV_PCM_INFO_MMAP_VALID |
55 SNDRV_PCM_INFO_BLOCK_TRANSFER, 54 SNDRV_PCM_INFO_BLOCK_TRANSFER,
56 .formats = SNDRV_PCM_FMTBIT_S16_LE | 55 .formats = SNDRV_PCM_FMTBIT_S16_LE |
@@ -67,10 +66,16 @@ static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
67static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, 66static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
68 struct snd_pcm_hw_params *params) 67 struct snd_pcm_hw_params *params)
69{ 68{
70 size_t size = bf5xx_pcm_hardware.buffer_bytes_max; 69 struct snd_soc_pcm_runtime *rtd = substream->private_data;
71 snd_pcm_lib_malloc_pages(substream, size); 70 unsigned int buffer_size = params_buffer_bytes(params);
71 struct bf5xx_i2s_pcm_data *dma_data;
72 72
73 return 0; 73 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
74
75 if (dma_data->tdm_mode)
76 buffer_size = buffer_size / params_channels(params) * 8;
77
78 return snd_pcm_lib_malloc_pages(substream, buffer_size);
74} 79}
75 80
76static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) 81static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
@@ -82,9 +87,16 @@ static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
82 87
83static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) 88static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
84{ 89{
90 struct snd_soc_pcm_runtime *rtd = substream->private_data;
85 struct snd_pcm_runtime *runtime = substream->runtime; 91 struct snd_pcm_runtime *runtime = substream->runtime;
86 struct sport_device *sport = runtime->private_data; 92 struct sport_device *sport = runtime->private_data;
87 int period_bytes = frames_to_bytes(runtime, runtime->period_size); 93 int period_bytes = frames_to_bytes(runtime, runtime->period_size);
94 struct bf5xx_i2s_pcm_data *dma_data;
95
96 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
97
98 if (dma_data->tdm_mode)
99 period_bytes = period_bytes / runtime->channels * 8;
88 100
89 pr_debug("%s enter\n", __func__); 101 pr_debug("%s enter\n", __func__);
90 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 102 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
@@ -131,10 +143,15 @@ static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
131 143
132static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) 144static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
133{ 145{
146 struct snd_soc_pcm_runtime *rtd = substream->private_data;
134 struct snd_pcm_runtime *runtime = substream->runtime; 147 struct snd_pcm_runtime *runtime = substream->runtime;
135 struct sport_device *sport = runtime->private_data; 148 struct sport_device *sport = runtime->private_data;
136 unsigned int diff; 149 unsigned int diff;
137 snd_pcm_uframes_t frames; 150 snd_pcm_uframes_t frames;
151 struct bf5xx_i2s_pcm_data *dma_data;
152
153 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
154
138 pr_debug("%s enter\n", __func__); 155 pr_debug("%s enter\n", __func__);
139 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 156 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
140 diff = sport_curr_offset_tx(sport); 157 diff = sport_curr_offset_tx(sport);
@@ -151,6 +168,8 @@ static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
151 diff = 0; 168 diff = 0;
152 169
153 frames = bytes_to_frames(substream->runtime, diff); 170 frames = bytes_to_frames(substream->runtime, diff);
171 if (dma_data->tdm_mode)
172 frames = frames * runtime->channels / 8;
154 173
155 return frames; 174 return frames;
156} 175}
@@ -162,11 +181,18 @@ static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
162 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); 181 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
163 struct snd_pcm_runtime *runtime = substream->runtime; 182 struct snd_pcm_runtime *runtime = substream->runtime;
164 struct snd_dma_buffer *buf = &substream->dma_buffer; 183 struct snd_dma_buffer *buf = &substream->dma_buffer;
184 struct bf5xx_i2s_pcm_data *dma_data;
165 int ret; 185 int ret;
166 186
187 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
188
167 pr_debug("%s enter\n", __func__); 189 pr_debug("%s enter\n", __func__);
168 190
169 snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware); 191 snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
192 if (dma_data->tdm_mode)
193 runtime->hw.buffer_bytes_max /= 4;
194 else
195 runtime->hw.info |= SNDRV_PCM_INFO_MMAP;
170 196
171 ret = snd_pcm_hw_constraint_integer(runtime, 197 ret = snd_pcm_hw_constraint_integer(runtime,
172 SNDRV_PCM_HW_PARAM_PERIODS); 198 SNDRV_PCM_HW_PARAM_PERIODS);
@@ -202,6 +228,88 @@ static int bf5xx_pcm_mmap(struct snd_pcm_substream *substream,
202 return 0 ; 228 return 0 ;
203} 229}
204 230
231static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
232 snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
233{
234 struct snd_soc_pcm_runtime *rtd = substream->private_data;
235 struct snd_pcm_runtime *runtime = substream->runtime;
236 unsigned int sample_size = runtime->sample_bits / 8;
237 struct bf5xx_i2s_pcm_data *dma_data;
238 unsigned int i;
239 void *src, *dst;
240
241 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
242
243 if (dma_data->tdm_mode) {
244 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
245 src = buf;
246 dst = runtime->dma_area;
247 dst += pos * sample_size * 8;
248
249 while (count--) {
250 for (i = 0; i < runtime->channels; i++) {
251 memcpy(dst + dma_data->map[i] *
252 sample_size, src, sample_size);
253 src += sample_size;
254 }
255 dst += 8 * sample_size;
256 }
257 } else {
258 src = runtime->dma_area;
259 src += pos * sample_size * 8;
260 dst = buf;
261
262 while (count--) {
263 for (i = 0; i < runtime->channels; i++) {
264 memcpy(dst, src + dma_data->map[i] *
265 sample_size, sample_size);
266 dst += sample_size;
267 }
268 src += 8 * sample_size;
269 }
270 }
271 } else {
272 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
273 src = buf;
274 dst = runtime->dma_area;
275 dst += frames_to_bytes(runtime, pos);
276 } else {
277 src = runtime->dma_area;
278 src += frames_to_bytes(runtime, pos);
279 dst = buf;
280 }
281
282 memcpy(dst, src, frames_to_bytes(runtime, count));
283 }
284
285 return 0;
286}
287
288static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
289 int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
290{
291 struct snd_soc_pcm_runtime *rtd = substream->private_data;
292 struct snd_pcm_runtime *runtime = substream->runtime;
293 unsigned int sample_size = runtime->sample_bits / 8;
294 void *buf = runtime->dma_area;
295 struct bf5xx_i2s_pcm_data *dma_data;
296 unsigned int offset, size;
297
298 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
299
300 if (dma_data->tdm_mode) {
301 offset = pos * 8 * sample_size;
302 size = count * 8 * sample_size;
303 } else {
304 offset = frames_to_bytes(runtime, pos);
305 size = frames_to_bytes(runtime, count);
306 }
307
308 snd_pcm_format_set_silence(runtime->format, buf + offset, size);
309
310 return 0;
311}
312
205static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { 313static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
206 .open = bf5xx_pcm_open, 314 .open = bf5xx_pcm_open,
207 .ioctl = snd_pcm_lib_ioctl, 315 .ioctl = snd_pcm_lib_ioctl,
@@ -211,57 +319,16 @@ static struct snd_pcm_ops bf5xx_pcm_i2s_ops = {
211 .trigger = bf5xx_pcm_trigger, 319 .trigger = bf5xx_pcm_trigger,
212 .pointer = bf5xx_pcm_pointer, 320 .pointer = bf5xx_pcm_pointer,
213 .mmap = bf5xx_pcm_mmap, 321 .mmap = bf5xx_pcm_mmap,
322 .copy = bf5xx_pcm_copy,
323 .silence = bf5xx_pcm_silence,
214}; 324};
215 325
216static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
217{
218 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
219 struct snd_dma_buffer *buf = &substream->dma_buffer;
220 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
221
222 buf->dev.type = SNDRV_DMA_TYPE_DEV;
223 buf->dev.dev = pcm->card->dev;
224 buf->private_data = NULL;
225 buf->area = dma_alloc_coherent(pcm->card->dev, size,
226 &buf->addr, GFP_KERNEL);
227 if (!buf->area) {
228 pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
229 return -ENOMEM;
230 }
231 buf->bytes = size;
232
233 pr_debug("%s, area:%p, size:0x%08lx\n", __func__,
234 buf->area, buf->bytes);
235
236 return 0;
237}
238
239static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
240{
241 struct snd_pcm_substream *substream;
242 struct snd_dma_buffer *buf;
243 int stream;
244
245 for (stream = 0; stream < 2; stream++) {
246 substream = pcm->streams[stream].substream;
247 if (!substream)
248 continue;
249
250 buf = &substream->dma_buffer;
251 if (!buf->area)
252 continue;
253 dma_free_coherent(NULL, buf->bytes, buf->area, 0);
254 buf->area = NULL;
255 }
256}
257
258static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); 326static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
259 327
260static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) 328static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
261{ 329{
262 struct snd_card *card = rtd->card->snd_card; 330 struct snd_card *card = rtd->card->snd_card;
263 struct snd_pcm *pcm = rtd->pcm; 331 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
264 int ret = 0;
265 332
266 pr_debug("%s enter\n", __func__); 333 pr_debug("%s enter\n", __func__);
267 if (!card->dev->dma_mask) 334 if (!card->dev->dma_mask)
@@ -269,27 +336,13 @@ static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
269 if (!card->dev->coherent_dma_mask) 336 if (!card->dev->coherent_dma_mask)
270 card->dev->coherent_dma_mask = DMA_BIT_MASK(32); 337 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
271 338
272 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { 339 return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm,
273 ret = bf5xx_pcm_preallocate_dma_buffer(pcm, 340 SNDRV_DMA_TYPE_DEV, card->dev, size, size);
274 SNDRV_PCM_STREAM_PLAYBACK);
275 if (ret)
276 goto out;
277 }
278
279 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
280 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
281 SNDRV_PCM_STREAM_CAPTURE);
282 if (ret)
283 goto out;
284 }
285 out:
286 return ret;
287} 341}
288 342
289static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = { 343static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = {
290 .ops = &bf5xx_pcm_i2s_ops, 344 .ops = &bf5xx_pcm_i2s_ops,
291 .pcm_new = bf5xx_pcm_i2s_new, 345 .pcm_new = bf5xx_pcm_i2s_new,
292 .pcm_free = bf5xx_pcm_free_dma_buffers,
293}; 346};
294 347
295static int bfin_i2s_soc_platform_probe(struct platform_device *pdev) 348static int bfin_i2s_soc_platform_probe(struct platform_device *pdev)
diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.h b/sound/soc/blackfin/bf5xx-i2s-pcm.h
index 0c2c5a68d4ff..1f0435249f88 100644
--- a/sound/soc/blackfin/bf5xx-i2s-pcm.h
+++ b/sound/soc/blackfin/bf5xx-i2s-pcm.h
@@ -1,26 +1,17 @@
1/* 1/*
2 * linux/sound/arm/bf5xx-i2s-pcm.h -- ALSA PCM interface for the Blackfin
3 *
4 * Copyright 2007 Analog Device Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify 2 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as 3 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. 4 * published by the Free Software Foundation.
9 */ 5 */
10 6
11#ifndef _BF5XX_I2S_PCM_H 7#ifndef _BF5XX_TDM_PCM_H
12#define _BF5XX_I2S_PCM_H 8#define _BF5XX_TDM_PCM_H
13 9
14struct bf5xx_pcm_dma_params { 10#define BFIN_TDM_DAI_MAX_SLOTS 8
15 char *name; /* stream identifier */
16};
17 11
18struct bf5xx_gpio { 12struct bf5xx_i2s_pcm_data {
19 u32 sys; 13 unsigned int map[BFIN_TDM_DAI_MAX_SLOTS];
20 u32 rx; 14 bool tdm_mode;
21 u32 tx;
22 u32 clk;
23 u32 frm;
24}; 15};
25 16
26#endif 17#endif
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c
index dd0c2a4f83a3..9a174fc47d39 100644
--- a/sound/soc/blackfin/bf5xx-i2s.c
+++ b/sound/soc/blackfin/bf5xx-i2s.c
@@ -42,6 +42,7 @@
42#include <linux/gpio.h> 42#include <linux/gpio.h>
43 43
44#include "bf5xx-sport.h" 44#include "bf5xx-sport.h"
45#include "bf5xx-i2s-pcm.h"
45 46
46struct bf5xx_i2s_port { 47struct bf5xx_i2s_port {
47 u16 tcr1; 48 u16 tcr1;
@@ -49,6 +50,13 @@ struct bf5xx_i2s_port {
49 u16 tcr2; 50 u16 tcr2;
50 u16 rcr2; 51 u16 rcr2;
51 int configured; 52 int configured;
53
54 unsigned int slots;
55 unsigned int tx_mask;
56 unsigned int rx_mask;
57
58 struct bf5xx_i2s_pcm_data tx_dma_data;
59 struct bf5xx_i2s_pcm_data rx_dma_data;
52}; 60};
53 61
54static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, 62static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -74,7 +82,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
74 ret = -EINVAL; 82 ret = -EINVAL;
75 break; 83 break;
76 default: 84 default:
77 printk(KERN_ERR "%s: Unknown DAI format type\n", __func__); 85 dev_err(cpu_dai->dev, "%s: Unknown DAI format type\n",
86 __func__);
78 ret = -EINVAL; 87 ret = -EINVAL;
79 break; 88 break;
80 } 89 }
@@ -88,7 +97,8 @@ static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
88 ret = -EINVAL; 97 ret = -EINVAL;
89 break; 98 break;
90 default: 99 default:
91 printk(KERN_ERR "%s: Unknown DAI master type\n", __func__); 100 dev_err(cpu_dai->dev, "%s: Unknown DAI master type\n",
101 __func__);
92 ret = -EINVAL; 102 ret = -EINVAL;
93 break; 103 break;
94 } 104 }
@@ -141,14 +151,14 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream,
141 ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, 151 ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
142 bf5xx_i2s->rcr2, 0, 0); 152 bf5xx_i2s->rcr2, 0, 0);
143 if (ret) { 153 if (ret) {
144 pr_err("SPORT is busy!\n"); 154 dev_err(dai->dev, "SPORT is busy!\n");
145 return -EBUSY; 155 return -EBUSY;
146 } 156 }
147 157
148 ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, 158 ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
149 bf5xx_i2s->tcr2, 0, 0); 159 bf5xx_i2s->tcr2, 0, 0);
150 if (ret) { 160 if (ret) {
151 pr_err("SPORT is busy!\n"); 161 dev_err(dai->dev, "SPORT is busy!\n");
152 return -EBUSY; 162 return -EBUSY;
153 } 163 }
154 } 164 }
@@ -162,18 +172,76 @@ static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream,
162 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); 172 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
163 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; 173 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
164 174
165 pr_debug("%s enter\n", __func__); 175 dev_dbg(dai->dev, "%s enter\n", __func__);
166 /* No active stream, SPORT is allowed to be configured again. */ 176 /* No active stream, SPORT is allowed to be configured again. */
167 if (!dai->active) 177 if (!dai->active)
168 bf5xx_i2s->configured = 0; 178 bf5xx_i2s->configured = 0;
169} 179}
170 180
181static int bf5xx_i2s_set_channel_map(struct snd_soc_dai *dai,
182 unsigned int tx_num, unsigned int *tx_slot,
183 unsigned int rx_num, unsigned int *rx_slot)
184{
185 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
186 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
187 unsigned int tx_mapped = 0, rx_mapped = 0;
188 unsigned int slot;
189 int i;
190
191 if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) ||
192 (rx_num > BFIN_TDM_DAI_MAX_SLOTS))
193 return -EINVAL;
194
195 for (i = 0; i < tx_num; i++) {
196 slot = tx_slot[i];
197 if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
198 (!(tx_mapped & (1 << slot)))) {
199 bf5xx_i2s->tx_dma_data.map[i] = slot;
200 tx_mapped |= 1 << slot;
201 } else
202 return -EINVAL;
203 }
204 for (i = 0; i < rx_num; i++) {
205 slot = rx_slot[i];
206 if ((slot < BFIN_TDM_DAI_MAX_SLOTS) &&
207 (!(rx_mapped & (1 << slot)))) {
208 bf5xx_i2s->rx_dma_data.map[i] = slot;
209 rx_mapped |= 1 << slot;
210 } else
211 return -EINVAL;
212 }
213
214 return 0;
215}
216
217static int bf5xx_i2s_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
218 unsigned int rx_mask, int slots, int width)
219{
220 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
221 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
222
223 if (slots % 8 != 0 || slots > 8)
224 return -EINVAL;
225
226 if (width != 32)
227 return -EINVAL;
228
229 bf5xx_i2s->slots = slots;
230 bf5xx_i2s->tx_mask = tx_mask;
231 bf5xx_i2s->rx_mask = rx_mask;
232
233 bf5xx_i2s->tx_dma_data.tdm_mode = slots != 0;
234 bf5xx_i2s->rx_dma_data.tdm_mode = slots != 0;
235
236 return sport_set_multichannel(sport_handle, slots, tx_mask, rx_mask, 0);
237}
238
171#ifdef CONFIG_PM 239#ifdef CONFIG_PM
172static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) 240static int bf5xx_i2s_suspend(struct snd_soc_dai *dai)
173{ 241{
174 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); 242 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
175 243
176 pr_debug("%s : sport %d\n", __func__, dai->id); 244 dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
177 245
178 if (dai->capture_active) 246 if (dai->capture_active)
179 sport_rx_stop(sport_handle); 247 sport_rx_stop(sport_handle);
@@ -188,23 +256,24 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
188 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; 256 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
189 int ret; 257 int ret;
190 258
191 pr_debug("%s : sport %d\n", __func__, dai->id); 259 dev_dbg(dai->dev, "%s : sport %d\n", __func__, dai->id);
192 260
193 ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, 261 ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1,
194 bf5xx_i2s->rcr2, 0, 0); 262 bf5xx_i2s->rcr2, 0, 0);
195 if (ret) { 263 if (ret) {
196 pr_err("SPORT is busy!\n"); 264 dev_err(dai->dev, "SPORT is busy!\n");
197 return -EBUSY; 265 return -EBUSY;
198 } 266 }
199 267
200 ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, 268 ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1,
201 bf5xx_i2s->tcr2, 0, 0); 269 bf5xx_i2s->tcr2, 0, 0);
202 if (ret) { 270 if (ret) {
203 pr_err("SPORT is busy!\n"); 271 dev_err(dai->dev, "SPORT is busy!\n");
204 return -EBUSY; 272 return -EBUSY;
205 } 273 }
206 274
207 return 0; 275 return sport_set_multichannel(sport_handle, bf5xx_i2s->slots,
276 bf5xx_i2s->tx_mask, bf5xx_i2s->rx_mask, 0);
208} 277}
209 278
210#else 279#else
@@ -212,6 +281,23 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
212#define bf5xx_i2s_resume NULL 281#define bf5xx_i2s_resume NULL
213#endif 282#endif
214 283
284static int bf5xx_i2s_dai_probe(struct snd_soc_dai *dai)
285{
286 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai);
287 struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data;
288 unsigned int i;
289
290 for (i = 0; i < BFIN_TDM_DAI_MAX_SLOTS; i++) {
291 bf5xx_i2s->tx_dma_data.map[i] = i;
292 bf5xx_i2s->rx_dma_data.map[i] = i;
293 }
294
295 dai->playback_dma_data = &bf5xx_i2s->tx_dma_data;
296 dai->capture_dma_data = &bf5xx_i2s->rx_dma_data;
297
298 return 0;
299}
300
215#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 301#define BF5XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
216 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ 302 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
217 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ 303 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
@@ -224,22 +310,25 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai)
224 SNDRV_PCM_FMTBIT_S32_LE) 310 SNDRV_PCM_FMTBIT_S32_LE)
225 311
226static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { 312static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = {
227 .shutdown = bf5xx_i2s_shutdown, 313 .shutdown = bf5xx_i2s_shutdown,
228 .hw_params = bf5xx_i2s_hw_params, 314 .hw_params = bf5xx_i2s_hw_params,
229 .set_fmt = bf5xx_i2s_set_dai_fmt, 315 .set_fmt = bf5xx_i2s_set_dai_fmt,
316 .set_tdm_slot = bf5xx_i2s_set_tdm_slot,
317 .set_channel_map = bf5xx_i2s_set_channel_map,
230}; 318};
231 319
232static struct snd_soc_dai_driver bf5xx_i2s_dai = { 320static struct snd_soc_dai_driver bf5xx_i2s_dai = {
321 .probe = bf5xx_i2s_dai_probe,
233 .suspend = bf5xx_i2s_suspend, 322 .suspend = bf5xx_i2s_suspend,
234 .resume = bf5xx_i2s_resume, 323 .resume = bf5xx_i2s_resume,
235 .playback = { 324 .playback = {
236 .channels_min = 1, 325 .channels_min = 2,
237 .channels_max = 2, 326 .channels_max = 8,
238 .rates = BF5XX_I2S_RATES, 327 .rates = BF5XX_I2S_RATES,
239 .formats = BF5XX_I2S_FORMATS,}, 328 .formats = BF5XX_I2S_FORMATS,},
240 .capture = { 329 .capture = {
241 .channels_min = 1, 330 .channels_min = 2,
242 .channels_max = 2, 331 .channels_max = 8,
243 .rates = BF5XX_I2S_RATES, 332 .rates = BF5XX_I2S_RATES,
244 .formats = BF5XX_I2S_FORMATS,}, 333 .formats = BF5XX_I2S_FORMATS,},
245 .ops = &bf5xx_i2s_dai_ops, 334 .ops = &bf5xx_i2s_dai_ops,
@@ -255,7 +344,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
255 int ret; 344 int ret;
256 345
257 /* configure SPORT for I2S */ 346 /* configure SPORT for I2S */
258 sport_handle = sport_init(pdev, 4, 2 * sizeof(u32), 347 sport_handle = sport_init(pdev, 4, 8 * sizeof(u32),
259 sizeof(struct bf5xx_i2s_port)); 348 sizeof(struct bf5xx_i2s_port));
260 if (!sport_handle) 349 if (!sport_handle)
261 return -ENODEV; 350 return -ENODEV;
@@ -264,7 +353,7 @@ static int bf5xx_i2s_probe(struct platform_device *pdev)
264 ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component, 353 ret = snd_soc_register_component(&pdev->dev, &bf5xx_i2s_component,
265 &bf5xx_i2s_dai, 1); 354 &bf5xx_i2s_dai, 1);
266 if (ret) { 355 if (ret) {
267 pr_err("Failed to register DAI: %d\n", ret); 356 dev_err(&pdev->dev, "Failed to register DAI: %d\n", ret);
268 sport_done(sport_handle); 357 sport_done(sport_handle);
269 return ret; 358 return ret;
270 } 359 }
@@ -276,7 +365,7 @@ static int bf5xx_i2s_remove(struct platform_device *pdev)
276{ 365{
277 struct sport_device *sport_handle = platform_get_drvdata(pdev); 366 struct sport_device *sport_handle = platform_get_drvdata(pdev);
278 367
279 pr_debug("%s enter\n", __func__); 368 dev_dbg(&pdev->dev, "%s enter\n", __func__);
280 369
281 snd_soc_unregister_component(&pdev->dev); 370 snd_soc_unregister_component(&pdev->dev);
282 sport_done(sport_handle); 371 sport_done(sport_handle);
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c
index 2fd9f2a06968..695351241db8 100644
--- a/sound/soc/blackfin/bf5xx-sport.c
+++ b/sound/soc/blackfin/bf5xx-sport.c
@@ -46,10 +46,10 @@
46/* note: multichannel is in units of 8 channels, 46/* note: multichannel is in units of 8 channels,
47 * tdm_count is # channels NOT / 8 ! */ 47 * tdm_count is # channels NOT / 8 ! */
48int sport_set_multichannel(struct sport_device *sport, 48int sport_set_multichannel(struct sport_device *sport,
49 int tdm_count, u32 mask, int packed) 49 int tdm_count, u32 tx_mask, u32 rx_mask, int packed)
50{ 50{
51 pr_debug("%s tdm_count=%d mask:0x%08x packed=%d\n", __func__, 51 pr_debug("%s tdm_count=%d tx_mask:0x%08x rx_mask:0x%08x packed=%d\n",
52 tdm_count, mask, packed); 52 __func__, tdm_count, tx_mask, rx_mask, packed);
53 53
54 if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN)) 54 if ((sport->regs->tcr1 & TSPEN) || (sport->regs->rcr1 & RSPEN))
55 return -EBUSY; 55 return -EBUSY;
@@ -65,8 +65,8 @@ int sport_set_multichannel(struct sport_device *sport,
65 sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \ 65 sport->regs->mcmc2 = FRAME_DELAY | MCMEN | \
66 (packed ? (MCDTXPE|MCDRXPE) : 0); 66 (packed ? (MCDTXPE|MCDRXPE) : 0);
67 67
68 sport->regs->mtcs0 = mask; 68 sport->regs->mtcs0 = tx_mask;
69 sport->regs->mrcs0 = mask; 69 sport->regs->mrcs0 = rx_mask;
70 sport->regs->mtcs1 = 0; 70 sport->regs->mtcs1 = 0;
71 sport->regs->mrcs1 = 0; 71 sport->regs->mrcs1 = 0;
72 sport->regs->mtcs2 = 0; 72 sport->regs->mtcs2 = 0;
diff --git a/sound/soc/blackfin/bf5xx-sport.h b/sound/soc/blackfin/bf5xx-sport.h
index 5ab60bd613ea..9fc2192feb3b 100644
--- a/sound/soc/blackfin/bf5xx-sport.h
+++ b/sound/soc/blackfin/bf5xx-sport.h
@@ -128,7 +128,7 @@ void sport_done(struct sport_device *sport);
128/* note: multichannel is in units of 8 channels, tdm_count is number of channels 128/* note: multichannel is in units of 8 channels, tdm_count is number of channels
129 * NOT / 8 ! all channels are enabled by default */ 129 * NOT / 8 ! all channels are enabled by default */
130int sport_set_multichannel(struct sport_device *sport, int tdm_count, 130int sport_set_multichannel(struct sport_device *sport, int tdm_count,
131 u32 mask, int packed); 131 u32 tx_mask, u32 rx_mask, int packed);
132 132
133int sport_config_rx(struct sport_device *sport, 133int sport_config_rx(struct sport_device *sport,
134 unsigned int rcr1, unsigned int rcr2, 134 unsigned int rcr1, unsigned int rcr2,
diff --git a/sound/soc/blackfin/bf5xx-ssm2602.c b/sound/soc/blackfin/bf5xx-ssm2602.c
index 7dbeef1099b4..9c19ccc936e2 100644
--- a/sound/soc/blackfin/bf5xx-ssm2602.c
+++ b/sound/soc/blackfin/bf5xx-ssm2602.c
@@ -40,7 +40,6 @@
40#include <linux/gpio.h> 40#include <linux/gpio.h>
41#include "../codecs/ssm2602.h" 41#include "../codecs/ssm2602.h"
42#include "bf5xx-sport.h" 42#include "bf5xx-sport.h"
43#include "bf5xx-i2s-pcm.h"
44 43
45static struct snd_soc_card bf5xx_ssm2602; 44static struct snd_soc_card bf5xx_ssm2602;
46 45
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c
deleted file mode 100644
index 0e6b888bb4cc..000000000000
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.c
+++ /dev/null
@@ -1,345 +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-pcm.h"
43#include "bf5xx-tdm.h"
44#include "bf5xx-sport.h"
45
46#define PCM_BUFFER_MAX 0x8000
47#define FRAGMENT_SIZE_MIN (4*1024)
48#define FRAGMENTS_MIN 2
49#define FRAGMENTS_MAX 32
50
51static void bf5xx_dma_irq(void *data)
52{
53 struct snd_pcm_substream *pcm = data;
54 snd_pcm_period_elapsed(pcm);
55}
56
57static const struct snd_pcm_hardware bf5xx_pcm_hardware = {
58 .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
59 SNDRV_PCM_INFO_RESUME),
60 .formats = SNDRV_PCM_FMTBIT_S32_LE,
61 .rates = SNDRV_PCM_RATE_48000,
62 .channels_min = 2,
63 .channels_max = 8,
64 .buffer_bytes_max = PCM_BUFFER_MAX,
65 .period_bytes_min = FRAGMENT_SIZE_MIN,
66 .period_bytes_max = PCM_BUFFER_MAX/2,
67 .periods_min = FRAGMENTS_MIN,
68 .periods_max = FRAGMENTS_MAX,
69};
70
71static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream,
72 struct snd_pcm_hw_params *params)
73{
74 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
75 snd_pcm_lib_malloc_pages(substream, size * 4);
76
77 return 0;
78}
79
80static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream)
81{
82 snd_pcm_lib_free_pages(substream);
83
84 return 0;
85}
86
87static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream)
88{
89 struct snd_pcm_runtime *runtime = substream->runtime;
90 struct sport_device *sport = runtime->private_data;
91 int fragsize_bytes = frames_to_bytes(runtime, runtime->period_size);
92
93 fragsize_bytes /= runtime->channels;
94 /* inflate the fragsize to match the dma width of SPORT */
95 fragsize_bytes *= 8;
96
97 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
98 sport_set_tx_callback(sport, bf5xx_dma_irq, substream);
99 sport_config_tx_dma(sport, runtime->dma_area,
100 runtime->periods, fragsize_bytes);
101 } else {
102 sport_set_rx_callback(sport, bf5xx_dma_irq, substream);
103 sport_config_rx_dma(sport, runtime->dma_area,
104 runtime->periods, fragsize_bytes);
105 }
106
107 return 0;
108}
109
110static int bf5xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
111{
112 struct snd_pcm_runtime *runtime = substream->runtime;
113 struct sport_device *sport = runtime->private_data;
114 int ret = 0;
115
116 switch (cmd) {
117 case SNDRV_PCM_TRIGGER_START:
118 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
119 sport_tx_start(sport);
120 else
121 sport_rx_start(sport);
122 break;
123 case SNDRV_PCM_TRIGGER_STOP:
124 case SNDRV_PCM_TRIGGER_SUSPEND:
125 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
126 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
127 sport_tx_stop(sport);
128 else
129 sport_rx_stop(sport);
130 break;
131 default:
132 ret = -EINVAL;
133 }
134
135 return ret;
136}
137
138static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream)
139{
140 struct snd_pcm_runtime *runtime = substream->runtime;
141 struct sport_device *sport = runtime->private_data;
142 unsigned int diff;
143 snd_pcm_uframes_t frames;
144
145 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
146 diff = sport_curr_offset_tx(sport);
147 frames = diff / (8*4); /* 32 bytes per frame */
148 } else {
149 diff = sport_curr_offset_rx(sport);
150 frames = diff / (8*4);
151 }
152 return frames;
153}
154
155static int bf5xx_pcm_open(struct snd_pcm_substream *substream)
156{
157 struct snd_soc_pcm_runtime *rtd = substream->private_data;
158 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
159 struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai);
160 struct snd_pcm_runtime *runtime = substream->runtime;
161 struct snd_dma_buffer *buf = &substream->dma_buffer;
162
163 int ret = 0;
164
165 snd_soc_set_runtime_hwparams(substream, &bf5xx_pcm_hardware);
166
167 ret = snd_pcm_hw_constraint_integer(runtime,
168 SNDRV_PCM_HW_PARAM_PERIODS);
169 if (ret < 0)
170 goto out;
171
172 if (sport_handle != NULL) {
173 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
174 sport_handle->tx_buf = buf->area;
175 else
176 sport_handle->rx_buf = buf->area;
177
178 runtime->private_data = sport_handle;
179 } else {
180 pr_err("sport_handle is NULL\n");
181 ret = -ENODEV;
182 }
183out:
184 return ret;
185}
186
187static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel,
188 snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count)
189{
190 struct snd_pcm_runtime *runtime = substream->runtime;
191 struct sport_device *sport = runtime->private_data;
192 struct bf5xx_tdm_port *tdm_port = sport->private_data;
193 unsigned int *src;
194 unsigned int *dst;
195 int i;
196
197 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
198 src = buf;
199 dst = (unsigned int *)substream->runtime->dma_area;
200
201 dst += pos * 8;
202 while (count--) {
203 for (i = 0; i < substream->runtime->channels; i++)
204 *(dst + tdm_port->tx_map[i]) = *src++;
205 dst += 8;
206 }
207 } else {
208 src = (unsigned int *)substream->runtime->dma_area;
209 dst = buf;
210
211 src += pos * 8;
212 while (count--) {
213 for (i = 0; i < substream->runtime->channels; i++)
214 *dst++ = *(src + tdm_port->rx_map[i]);
215 src += 8;
216 }
217 }
218
219 return 0;
220}
221
222static int bf5xx_pcm_silence(struct snd_pcm_substream *substream,
223 int channel, snd_pcm_uframes_t pos, snd_pcm_uframes_t count)
224{
225 unsigned char *buf = substream->runtime->dma_area;
226 buf += pos * 8 * 4;
227 memset(buf, '\0', count * 8 * 4);
228
229 return 0;
230}
231
232
233struct snd_pcm_ops bf5xx_pcm_tdm_ops = {
234 .open = bf5xx_pcm_open,
235 .ioctl = snd_pcm_lib_ioctl,
236 .hw_params = bf5xx_pcm_hw_params,
237 .hw_free = bf5xx_pcm_hw_free,
238 .prepare = bf5xx_pcm_prepare,
239 .trigger = bf5xx_pcm_trigger,
240 .pointer = bf5xx_pcm_pointer,
241 .copy = bf5xx_pcm_copy,
242 .silence = bf5xx_pcm_silence,
243};
244
245static int bf5xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
246{
247 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
248 struct snd_dma_buffer *buf = &substream->dma_buffer;
249 size_t size = bf5xx_pcm_hardware.buffer_bytes_max;
250
251 buf->dev.type = SNDRV_DMA_TYPE_DEV;
252 buf->dev.dev = pcm->card->dev;
253 buf->private_data = NULL;
254 buf->area = dma_alloc_coherent(pcm->card->dev, size * 4,
255 &buf->addr, GFP_KERNEL);
256 if (!buf->area) {
257 pr_err("Failed to allocate dma memory - Please increase uncached DMA memory region\n");
258 return -ENOMEM;
259 }
260 buf->bytes = size;
261
262 return 0;
263}
264
265static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
266{
267 struct snd_pcm_substream *substream;
268 struct snd_dma_buffer *buf;
269 int stream;
270
271 for (stream = 0; stream < 2; stream++) {
272 substream = pcm->streams[stream].substream;
273 if (!substream)
274 continue;
275
276 buf = &substream->dma_buffer;
277 if (!buf->area)
278 continue;
279 dma_free_coherent(NULL, buf->bytes, buf->area, 0);
280 buf->area = NULL;
281 }
282}
283
284static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
285
286static int bf5xx_pcm_tdm_new(struct snd_soc_pcm_runtime *rtd)
287{
288 struct snd_card *card = rtd->card->snd_card;
289 struct snd_pcm *pcm = rtd->pcm;
290 int ret = 0;
291
292 if (!card->dev->dma_mask)
293 card->dev->dma_mask = &bf5xx_pcm_dmamask;
294 if (!card->dev->coherent_dma_mask)
295 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
296
297 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
298 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
299 SNDRV_PCM_STREAM_PLAYBACK);
300 if (ret)
301 goto out;
302 }
303
304 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
305 ret = bf5xx_pcm_preallocate_dma_buffer(pcm,
306 SNDRV_PCM_STREAM_CAPTURE);
307 if (ret)
308 goto out;
309 }
310out:
311 return ret;
312}
313
314static struct snd_soc_platform_driver bf5xx_tdm_soc_platform = {
315 .ops = &bf5xx_pcm_tdm_ops,
316 .pcm_new = bf5xx_pcm_tdm_new,
317 .pcm_free = bf5xx_pcm_free_dma_buffers,
318};
319
320static int bf5xx_soc_platform_probe(struct platform_device *pdev)
321{
322 return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform);
323}
324
325static int bf5xx_soc_platform_remove(struct platform_device *pdev)
326{
327 snd_soc_unregister_platform(&pdev->dev);
328 return 0;
329}
330
331static struct platform_driver bfin_tdm_driver = {
332 .driver = {
333 .name = "bfin-tdm-pcm-audio",
334 .owner = THIS_MODULE,
335 },
336
337 .probe = bf5xx_soc_platform_probe,
338 .remove = bf5xx_soc_platform_remove,
339};
340
341module_platform_driver(bfin_tdm_driver);
342
343MODULE_AUTHOR("Barry Song");
344MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module");
345MODULE_LICENSE("GPL");
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.h b/sound/soc/blackfin/bf5xx-tdm-pcm.h
deleted file mode 100644
index 7f8cc01c4477..000000000000
--- a/sound/soc/blackfin/bf5xx-tdm-pcm.h
+++ /dev/null
@@ -1,18 +0,0 @@
1/*
2 * sound/soc/blackfin/bf5xx-tdm-pcm.h -- ALSA PCM interface for the Blackfin
3 *
4 * Copyright 2009 Analog Device Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#ifndef _BF5XX_TDM_PCM_H
12#define _BF5XX_TDM_PCM_H
13
14struct bf5xx_pcm_dma_params {
15 char *name; /* stream identifier */
16};
17
18#endif
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c
deleted file mode 100644
index 69e9a3e935bd..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, 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, 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