aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.c200
-rw-r--r--sound/soc/pxa/pxa2xx-i2s.h20
2 files changed, 102 insertions, 118 deletions
diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c
index 98b167fe68e5..575a6137c040 100644
--- a/sound/soc/pxa/pxa2xx-i2s.c
+++ b/sound/soc/pxa/pxa2xx-i2s.c
@@ -29,11 +29,7 @@
29#include <asm/arch/audio.h> 29#include <asm/arch/audio.h>
30 30
31#include "pxa2xx-pcm.h" 31#include "pxa2xx-pcm.h"
32 32#include "pxa2xx-i2s.h"
33/* used to disable sysclk if external crystal is used */
34static int extclk;
35module_param(extclk, int, 0);
36MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk");
37 33
38struct pxa_i2s_port { 34struct pxa_i2s_port {
39 u32 sadiv; 35 u32 sadiv;
@@ -41,97 +37,10 @@ struct pxa_i2s_port {
41 u32 sacr1; 37 u32 sacr1;
42 u32 saimr; 38 u32 saimr;
43 int master; 39 int master;
40 u32 fmt;
44}; 41};
45static struct pxa_i2s_port pxa_i2s; 42static struct pxa_i2s_port pxa_i2s;
46 43
47#define PXA_I2S_DAIFMT \
48 (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF)
49
50#define PXA_I2S_DIR \
51 (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
52
53#define PXA_I2S_RATES \
54 (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
55 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
56 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
57
58/* priv is divider */
59static struct snd_soc_dai_mode pxa2xx_i2s_modes[] = {
60 /* pxa2xx I2S frame and clock master modes */
61 {
62 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
63 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
64 .pcmrate = SNDRV_PCM_RATE_8000,
65 .pcmdir = PXA_I2S_DIR,
66 .flags = SND_SOC_DAI_BFS_DIV,
67 .fs = 256,
68 .bfs = SND_SOC_FSBD(4),
69 .priv = 0x48,
70 },
71 {
72 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
73 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
74 .pcmrate = SNDRV_PCM_RATE_11025,
75 .pcmdir = PXA_I2S_DIR,
76 .flags = SND_SOC_DAI_BFS_DIV,
77 .fs = 256,
78 .bfs = SND_SOC_FSBD(4),
79 .priv = 0x34,
80 },
81 {
82 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
83 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
84 .pcmrate = SNDRV_PCM_RATE_16000,
85 .pcmdir = PXA_I2S_DIR,
86 .flags = SND_SOC_DAI_BFS_DIV,
87 .fs = 256,
88 .bfs = SND_SOC_FSBD(4),
89 .priv = 0x24,
90 },
91 {
92 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
93 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
94 .pcmrate = SNDRV_PCM_RATE_22050,
95 .pcmdir = PXA_I2S_DIR,
96 .flags = SND_SOC_DAI_BFS_DIV,
97 .fs = 256,
98 .bfs = SND_SOC_FSBD(4),
99 .priv = 0x1a,
100 },
101 {
102 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
103 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
104 .pcmrate = SNDRV_PCM_RATE_44100,
105 .pcmdir = PXA_I2S_DIR,
106 .flags = SND_SOC_DAI_BFS_DIV,
107 .fs = 256,
108 .bfs = SND_SOC_FSBD(4),
109 .priv = 0xd,
110 },
111 {
112 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
113 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
114 .pcmrate = SNDRV_PCM_RATE_48000,
115 .pcmdir = PXA_I2S_DIR,
116 .flags = SND_SOC_DAI_BFS_DIV,
117 .fs = 256,
118 .bfs = SND_SOC_FSBD(4),
119 .priv = 0xc,
120 },
121
122 /* pxa2xx I2S frame master and clock slave mode */
123 {
124 .fmt = PXA_I2S_DAIFMT | SND_SOC_DAIFMT_CBM_CFS,
125 .pcmfmt = SNDRV_PCM_FMTBIT_S16_LE,
126 .pcmrate = PXA_I2S_RATES,
127 .pcmdir = PXA_I2S_DIR,
128 .fs = SND_SOC_FS_ALL,
129 .flags = SND_SOC_DAI_BFS_RATE,
130 .bfs = 64,
131 .priv = 0x48,
132 },
133};
134
135static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { 44static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = {
136 .name = "I2S PCM Stereo out", 45 .name = "I2S PCM Stereo out",
137 .dev_addr = __PREG(SADR), 46 .dev_addr = __PREG(SADR),
@@ -171,8 +80,9 @@ static struct pxa2xx_gpio gpio_bus[] = {
171static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) 80static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream)
172{ 81{
173 struct snd_soc_pcm_runtime *rtd = substream->private_data; 82 struct snd_soc_pcm_runtime *rtd = substream->private_data;
83 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
174 84
175 if (!rtd->cpu_dai->active) { 85 if (!cpu_dai->active) {
176 SACR0 |= SACR0_RST; 86 SACR0 |= SACR0_RST;
177 SACR0 = 0; 87 SACR0 = 0;
178 } 88 }
@@ -191,18 +101,50 @@ static int pxa_i2s_wait(void)
191 return 0; 101 return 0;
192} 102}
193 103
194static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, 104static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_cpu_dai *cpu_dai,
195 struct snd_pcm_hw_params *params) 105 unsigned int fmt)
196{ 106{
197 struct snd_soc_pcm_runtime *rtd = substream->private_data; 107 /* interface format */
108 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
109 case SND_SOC_DAIFMT_I2S:
110 pxa_i2s.fmt = 0;
111 break;
112 case SND_SOC_DAIFMT_LEFT_J:
113 pxa_i2s.fmt = SACR1_AMSL;
114 break;
115 }
198 116
199 pxa_i2s.master = 0; 117 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
200 if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_CBS_CFS) 118 case SND_SOC_DAIFMT_CBS_CFS:
201 pxa_i2s.master = 1; 119 pxa_i2s.master = 1;
120 break;
121 case SND_SOC_DAIFMT_CBM_CFS:
122 pxa_i2s.master = 0;
123 break;
124 default:
125 break;
126 }
127 return 0;
128}
202 129
203 if (pxa_i2s.master && !extclk) 130static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_cpu_dai *cpu_dai,
131 int clk_id, unsigned int freq, int dir)
132{
133 if (clk_id != PXA2XX_I2S_SYSCLK)
134 return -ENODEV;
135
136 if (pxa_i2s.master && dir == SND_SOC_CLOCK_OUT)
204 pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys); 137 pxa_gpio_mode(gpio_bus[pxa_i2s.master].sys);
205 138
139 return 0;
140}
141
142static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
143 struct snd_pcm_hw_params *params)
144{
145 struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 struct snd_soc_cpu_dai *cpu_dai = rtd->dai->cpu_dai;
147
206 pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx); 148 pxa_gpio_mode(gpio_bus[pxa_i2s.master].rx);
207 pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx); 149 pxa_gpio_mode(gpio_bus[pxa_i2s.master].tx);
208 pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm); 150 pxa_gpio_mode(gpio_bus[pxa_i2s.master].frm);
@@ -211,9 +153,9 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
211 pxa_i2s_wait(); 153 pxa_i2s_wait();
212 154
213 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 155 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
214 rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out; 156 cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_out;
215 else 157 else
216 rtd->cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in; 158 cpu_dai->dma_data = &pxa2xx_i2s_pcm_stereo_in;
217 159
218 /* is port used by another stream */ 160 /* is port used by another stream */
219 if (!(SACR0 & SACR0_ENB)) { 161 if (!(SACR0 & SACR0_ENB)) {
@@ -224,16 +166,37 @@ static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
224 SACR0 |= SACR0_BCKD; 166 SACR0 |= SACR0_BCKD;
225 167
226 SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1); 168 SACR0 |= SACR0_RFTH(14) | SACR0_TFTH(1);
227 169 SACR1 |= pxa_i2s.fmt;
228 if (rtd->cpu_dai->dai_runtime.fmt & SND_SOC_DAIFMT_LEFT_J)
229 SACR1 |= SACR1_AMSL;
230 } 170 }
231 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 171 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
232 SAIMR |= SAIMR_TFS; 172 SAIMR |= SAIMR_TFS;
233 else 173 else
234 SAIMR |= SAIMR_RFS; 174 SAIMR |= SAIMR_RFS;
235 175
236 SADIV = rtd->cpu_dai->dai_runtime.priv; 176 switch (params_rate(params)) {
177 case 8000:
178 SADIV = 0x48;
179 break;
180 case 11025:
181 SADIV = 0x34;
182 break;
183 case 16000:
184 SADIV = 0x24;
185 break;
186 case 22050:
187 SADIV = 0x1a;
188 break;
189 case 44100:
190 SADIV = 0xd;
191 break;
192 case 48000:
193 SADIV = 0xc;
194 break;
195 case 96000: /* not in manual and possibly slightly inaccurate */
196 SADIV = 0x6;
197 break;
198 }
199
237 return 0; 200 return 0;
238} 201}
239 202
@@ -316,12 +279,9 @@ static int pxa2xx_i2s_resume(struct platform_device *pdev,
316#define pxa2xx_i2s_resume NULL 279#define pxa2xx_i2s_resume NULL
317#endif 280#endif
318 281
319/* pxa2xx I2S sysclock is always 256 FS */ 282#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
320static unsigned int pxa_i2s_config_sysclk(struct snd_soc_cpu_dai *iface, 283 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
321 struct snd_soc_clock_info *info, unsigned int clk) 284 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
322{
323 return info->rate << 8;
324}
325 285
326struct snd_soc_cpu_dai pxa_i2s_dai = { 286struct snd_soc_cpu_dai pxa_i2s_dai = {
327 .name = "pxa2xx-i2s", 287 .name = "pxa2xx-i2s",
@@ -329,21 +289,25 @@ struct snd_soc_cpu_dai pxa_i2s_dai = {
329 .type = SND_SOC_DAI_I2S, 289 .type = SND_SOC_DAI_I2S,
330 .suspend = pxa2xx_i2s_suspend, 290 .suspend = pxa2xx_i2s_suspend,
331 .resume = pxa2xx_i2s_resume, 291 .resume = pxa2xx_i2s_resume,
332 .config_sysclk = pxa_i2s_config_sysclk,
333 .playback = { 292 .playback = {
334 .channels_min = 2, 293 .channels_min = 2,
335 .channels_max = 2,}, 294 .channels_max = 2,
295 .rates = PXA2XX_I2S_RATES,
296 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
336 .capture = { 297 .capture = {
337 .channels_min = 2, 298 .channels_min = 2,
338 .channels_max = 2,}, 299 .channels_max = 2,
300 .rates = PXA2XX_I2S_RATES,
301 .formats = SNDRV_PCM_FMTBIT_S16_LE,},
339 .ops = { 302 .ops = {
340 .startup = pxa2xx_i2s_startup, 303 .startup = pxa2xx_i2s_startup,
341 .shutdown = pxa2xx_i2s_shutdown, 304 .shutdown = pxa2xx_i2s_shutdown,
342 .trigger = pxa2xx_i2s_trigger, 305 .trigger = pxa2xx_i2s_trigger,
343 .hw_params = pxa2xx_i2s_hw_params,}, 306 .hw_params = pxa2xx_i2s_hw_params,},
344 .caps = { 307 .dai_ops = {
345 .num_modes = ARRAY_SIZE(pxa2xx_i2s_modes), 308 .set_fmt = pxa2xx_i2s_set_dai_fmt,
346 .mode = pxa2xx_i2s_modes,}, 309 .set_sysclk = pxa2xx_i2s_set_dai_sysclk,
310 },
347}; 311};
348 312
349EXPORT_SYMBOL_GPL(pxa_i2s_dai); 313EXPORT_SYMBOL_GPL(pxa_i2s_dai);
diff --git a/sound/soc/pxa/pxa2xx-i2s.h b/sound/soc/pxa/pxa2xx-i2s.h
new file mode 100644
index 000000000000..a2484f0881f1
--- /dev/null
+++ b/sound/soc/pxa/pxa2xx-i2s.h
@@ -0,0 +1,20 @@
1/*
2 * linux/sound/arm/pxa2xx-i2s.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 _PXA2XX_I2S_H
10#define _PXA2XX_I2S_H
11
12/* pxa2xx DAI ID's */
13#define PXA2XX_DAI_I2S 0
14
15/* I2S clock */
16#define PXA2XX_I2S_SYSCLK 0
17
18extern struct snd_soc_cpu_dai pxa_i2s_dai;
19
20#endif