diff options
Diffstat (limited to 'sound/soc')
-rw-r--r-- | sound/soc/pxa/pxa2xx-i2s.c | 200 | ||||
-rw-r--r-- | sound/soc/pxa/pxa2xx-i2s.h | 20 |
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 */ | ||
34 | static int extclk; | ||
35 | module_param(extclk, int, 0); | ||
36 | MODULE_PARM_DESC(extclk, "set to 1 to disable pxa2xx i2s sysclk"); | ||
37 | 33 | ||
38 | struct pxa_i2s_port { | 34 | struct 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 | }; |
45 | static struct pxa_i2s_port pxa_i2s; | 42 | static 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 */ | ||
59 | static 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 | |||
135 | static struct pxa2xx_pcm_dma_params pxa2xx_i2s_pcm_stereo_out = { | 44 | static 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[] = { | |||
171 | static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream) | 80 | static 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 | ||
194 | static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream, | 104 | static 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) | 130 | static 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 | |||
142 | static 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 |\ |
320 | static 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 | ||
326 | struct snd_soc_cpu_dai pxa_i2s_dai = { | 286 | struct 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 | ||
349 | EXPORT_SYMBOL_GPL(pxa_i2s_dai); | 313 | EXPORT_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 | |||
18 | extern struct snd_soc_cpu_dai pxa_i2s_dai; | ||
19 | |||
20 | #endif | ||