diff options
Diffstat (limited to 'sound/soc/blackfin')
-rw-r--r-- | sound/soc/blackfin/Kconfig | 47 | ||||
-rw-r--r-- | sound/soc/blackfin/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97-pcm.c | 1 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97-pcm.h | 26 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ac97.c | 37 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ad1836.c | 19 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ad193x.c | 40 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ad1980.c | 1 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ad73311.c | 1 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s-pcm.c | 183 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s-pcm.h | 21 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s.c | 129 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-sport.c | 10 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-sport.h | 2 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-ssm2602.c | 1 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-tdm-pcm.c | 345 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-tdm-pcm.h | 18 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-tdm.c | 328 | ||||
-rw-r--r-- | sound/soc/blackfin/bf5xx-tdm.h | 23 |
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 | ||
59 | config 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 | |||
67 | config 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 | |||
59 | config SND_BF5XX_SOC_AD73311 | 76 | config 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 | ||
75 | config 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 | |||
85 | config 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 | |||
93 | config 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 | |||
102 | config SND_BF5XX_AC97 | 92 | config 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 | |||
174 | config SND_BF6XX_SOC_I2S | 164 | config SND_BF6XX_SOC_I2S |
175 | tristate | 165 | tristate |
176 | 166 | ||
177 | config SND_BF5XX_SOC_TDM | ||
178 | tristate | ||
179 | |||
180 | config SND_BF5XX_SOC_AC97 | 167 | config 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 |
2 | snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o | 2 | snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o |
3 | snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o | 3 | snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o |
4 | snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o | ||
5 | snd-soc-bf5xx-sport-objs := bf5xx-sport.o | 4 | snd-soc-bf5xx-sport-objs := bf5xx-sport.o |
6 | snd-soc-bf6xx-sport-objs := bf6xx-sport.o | 5 | snd-soc-bf6xx-sport-objs := bf6xx-sport.o |
7 | snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o | 6 | snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o |
8 | snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o | 7 | snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o |
9 | snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o | 8 | snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o |
10 | snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o | ||
11 | 9 | ||
12 | obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o | 10 | obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o |
13 | obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o | 11 | obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o |
14 | obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o | ||
15 | obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o | 12 | obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o |
16 | obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o | 13 | obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o |
17 | obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o | 14 | obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o |
18 | obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o | 15 | obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o |
19 | obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o | 16 | obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o |
20 | obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o | ||
21 | 17 | ||
22 | # Blackfin Machine Support | 18 | # Blackfin Machine Support |
23 | snd-ad1836-objs := bf5xx-ad1836.o | 19 | snd-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 | |||
14 | struct bf5xx_pcm_dma_params { | ||
15 | char *name; /* stream identifier */ | ||
16 | }; | ||
17 | |||
18 | struct 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 | ||
201 | struct snd_ac97_bus_ops soc_ac97_ops = { | 201 | static 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 | }; |
207 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
208 | 207 | ||
209 | #ifdef CONFIG_PM | 208 | #ifdef CONFIG_PM |
210 | static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) | 209 | static 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) | |||
349 | sport_config_err: | 355 | sport_config_err: |
350 | sport_done(sport_handle); | 356 | sport_done(sport_handle); |
351 | sport_err: | 357 | sport_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); | ||
354 | gpio_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 | |||
36 | static struct snd_soc_card bf5xx_ad1836; | 33 | static struct snd_soc_card bf5xx_ad1836; |
37 | 34 | ||
38 | static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, | 35 | static 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 | ||
55 | static 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 | ||
71 | static struct snd_soc_card bf5xx_ad1836 = { | 66 | static 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 | |||
45 | static struct snd_soc_card bf5xx_ad193x; | 42 | static struct snd_soc_card bf5xx_ad193x; |
46 | 43 | ||
47 | static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream, | 44 | static 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 | ||
86 | static struct snd_soc_ops bf5xx_ad193x_ops = { | ||
87 | .hw_params = bf5xx_ad193x_hw_params, | ||
88 | }; | ||
89 | |||
90 | static struct snd_soc_dai_link bf5xx_ad193x_dai[] = { | 70 | static 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 | ||
54 | static struct snd_soc_card bf5xx_board; | 53 | static 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 | ||
45 | static void bf5xx_dma_irq(void *data) | 45 | static void bf5xx_dma_irq(void *data) |
46 | { | 46 | { |
@@ -50,7 +50,6 @@ static void bf5xx_dma_irq(void *data) | |||
50 | 50 | ||
51 | static const struct snd_pcm_hardware bf5xx_pcm_hardware = { | 51 | static 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 = { | |||
67 | static int bf5xx_pcm_hw_params(struct snd_pcm_substream *substream, | 66 | static 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 | ||
76 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | 81 | static 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 | ||
83 | static int bf5xx_pcm_prepare(struct snd_pcm_substream *substream) | 88 | static 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 | ||
132 | static snd_pcm_uframes_t bf5xx_pcm_pointer(struct snd_pcm_substream *substream) | 144 | static 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 | ||
231 | static 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 | |||
288 | static 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 | |||
205 | static struct snd_pcm_ops bf5xx_pcm_i2s_ops = { | 313 | static 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 | ||
216 | static 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 | |||
239 | static 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 | |||
258 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); | 326 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); |
259 | 327 | ||
260 | static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) | 328 | static 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 | ||
289 | static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = { | 343 | static 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 | ||
295 | static int bfin_i2s_soc_platform_probe(struct platform_device *pdev) | 348 | static 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 | ||
14 | struct bf5xx_pcm_dma_params { | 10 | #define BFIN_TDM_DAI_MAX_SLOTS 8 |
15 | char *name; /* stream identifier */ | ||
16 | }; | ||
17 | 11 | ||
18 | struct bf5xx_gpio { | 12 | struct 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 | ||
46 | struct bf5xx_i2s_port { | 47 | struct 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 | ||
54 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 62 | static 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 | ||
181 | static 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 | |||
217 | static 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 |
172 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | 240 | static 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 | ||
284 | static 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 | ||
226 | static const struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | 312 | static 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 | ||
232 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { | 320 | static 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 ! */ |
48 | int sport_set_multichannel(struct sport_device *sport, | 48 | int 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 */ |
130 | int sport_set_multichannel(struct sport_device *sport, int tdm_count, | 130 | int 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 | ||
133 | int sport_config_rx(struct sport_device *sport, | 133 | int 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 | ||
45 | static struct snd_soc_card bf5xx_ssm2602; | 44 | static 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 | |||
51 | static void bf5xx_dma_irq(void *data) | ||
52 | { | ||
53 | struct snd_pcm_substream *pcm = data; | ||
54 | snd_pcm_period_elapsed(pcm); | ||
55 | } | ||
56 | |||
57 | static 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 | |||
71 | static 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 | |||
80 | static int bf5xx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
81 | { | ||
82 | snd_pcm_lib_free_pages(substream); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static 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 | |||
110 | static 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 | |||
138 | static 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 | |||
155 | static 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 | } | ||
183 | out: | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | static 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 | |||
222 | static 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 | |||
233 | struct 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 | |||
245 | static 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 | |||
265 | static 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 | |||
284 | static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); | ||
285 | |||
286 | static 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 | } | ||
310 | out: | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | static 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 | |||
320 | static int bf5xx_soc_platform_probe(struct platform_device *pdev) | ||
321 | { | ||
322 | return snd_soc_register_platform(&pdev->dev, &bf5xx_tdm_soc_platform); | ||
323 | } | ||
324 | |||
325 | static int bf5xx_soc_platform_remove(struct platform_device *pdev) | ||
326 | { | ||
327 | snd_soc_unregister_platform(&pdev->dev); | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | static 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 | |||
341 | module_platform_driver(bfin_tdm_driver); | ||
342 | |||
343 | MODULE_AUTHOR("Barry Song"); | ||
344 | MODULE_DESCRIPTION("ADI Blackfin TDM PCM DMA module"); | ||
345 | MODULE_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 | |||
14 | struct 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 | |||
49 | static 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 | |||
81 | static 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 | |||
133 | static 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 | |||
144 | static 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 | ||
181 | static 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 | |||
196 | static 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 | |||
229 | static 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 | |||
236 | static 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 | |||
252 | static const struct snd_soc_component_driver bf5xx_tdm_component = { | ||
253 | .name = "bf5xx-tdm", | ||
254 | }; | ||
255 | |||
256 | static 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 | |||
298 | sport_config_err: | ||
299 | sport_done(sport_handle); | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static 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 | |||
313 | static 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 | |||
322 | module_platform_driver(bfin_tdm_driver); | ||
323 | |||
324 | /* Module information */ | ||
325 | MODULE_AUTHOR("Barry Song"); | ||
326 | MODULE_DESCRIPTION("TDM driver for ADI Blackfin"); | ||
327 | MODULE_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 | ||
13 | struct 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 | ||