diff options
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r-- | sound/soc/omap/omap-mcbsp.c | 123 |
1 files changed, 107 insertions, 16 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index a5d46a7b196a..3341f49402ca 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -139,27 +139,67 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { | |||
139 | static const unsigned long omap34xx_mcbsp_port[][2] = {}; | 139 | static const unsigned long omap34xx_mcbsp_port[][2] = {}; |
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) | ||
143 | { | ||
144 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
145 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
146 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | ||
147 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); | ||
148 | int samples; | ||
149 | |||
150 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | ||
151 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | ||
152 | samples = snd_pcm_lib_period_bytes(substream) >> 1; | ||
153 | else | ||
154 | samples = 1; | ||
155 | |||
156 | /* Configure McBSP internal buffer usage */ | ||
157 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
158 | omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); | ||
159 | else | ||
160 | omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); | ||
161 | } | ||
162 | |||
142 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, | 163 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, |
143 | struct snd_soc_dai *dai) | 164 | struct snd_soc_dai *dai) |
144 | { | 165 | { |
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 166 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
146 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 167 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
147 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 168 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
169 | int bus_id = mcbsp_data->bus_id; | ||
148 | int err = 0; | 170 | int err = 0; |
149 | 171 | ||
150 | if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) { | 172 | if (!cpu_dai->active) |
173 | err = omap_mcbsp_request(bus_id); | ||
174 | |||
175 | if (cpu_is_omap343x()) { | ||
176 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); | ||
177 | int max_period; | ||
178 | |||
151 | /* | 179 | /* |
152 | * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. | 180 | * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. |
153 | * Set constraint for minimum buffer size to the same than FIFO | 181 | * Set constraint for minimum buffer size to the same than FIFO |
154 | * size in order to avoid underruns in playback startup because | 182 | * size in order to avoid underruns in playback startup because |
155 | * HW is keeping the DMA request active until FIFO is filled. | 183 | * HW is keeping the DMA request active until FIFO is filled. |
156 | */ | 184 | */ |
157 | snd_pcm_hw_constraint_minmax(substream->runtime, | 185 | if (bus_id == 1) |
158 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX); | 186 | snd_pcm_hw_constraint_minmax(substream->runtime, |
159 | } | 187 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
188 | 4096, UINT_MAX); | ||
160 | 189 | ||
161 | if (!cpu_dai->active) | 190 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
162 | err = omap_mcbsp_request(mcbsp_data->bus_id); | 191 | max_period = omap_mcbsp_get_max_tx_threshold(bus_id); |
192 | else | ||
193 | max_period = omap_mcbsp_get_max_rx_threshold(bus_id); | ||
194 | |||
195 | max_period++; | ||
196 | max_period <<= 1; | ||
197 | |||
198 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | ||
199 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
200 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
201 | 32, max_period); | ||
202 | } | ||
163 | 203 | ||
164 | return err; | 204 | return err; |
165 | } | 205 | } |
@@ -183,21 +223,21 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
183 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 223 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
184 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 224 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
185 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 225 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
186 | int err = 0; | 226 | int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); |
187 | 227 | ||
188 | switch (cmd) { | 228 | switch (cmd) { |
189 | case SNDRV_PCM_TRIGGER_START: | 229 | case SNDRV_PCM_TRIGGER_START: |
190 | case SNDRV_PCM_TRIGGER_RESUME: | 230 | case SNDRV_PCM_TRIGGER_RESUME: |
191 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 231 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
192 | if (!mcbsp_data->active++) | 232 | mcbsp_data->active++; |
193 | omap_mcbsp_start(mcbsp_data->bus_id); | 233 | omap_mcbsp_start(mcbsp_data->bus_id, play, !play); |
194 | break; | 234 | break; |
195 | 235 | ||
196 | case SNDRV_PCM_TRIGGER_STOP: | 236 | case SNDRV_PCM_TRIGGER_STOP: |
197 | case SNDRV_PCM_TRIGGER_SUSPEND: | 237 | case SNDRV_PCM_TRIGGER_SUSPEND: |
198 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 238 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
199 | if (!--mcbsp_data->active) | 239 | omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); |
200 | omap_mcbsp_stop(mcbsp_data->bus_id); | 240 | mcbsp_data->active--; |
201 | break; | 241 | break; |
202 | default: | 242 | default: |
203 | err = -EINVAL; | 243 | err = -EINVAL; |
@@ -215,7 +255,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
215 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 255 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
216 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; | 256 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; |
217 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; | 257 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; |
218 | int wlen, channels, wpf; | 258 | int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; |
219 | unsigned long port; | 259 | unsigned long port; |
220 | unsigned int format; | 260 | unsigned int format; |
221 | 261 | ||
@@ -231,6 +271,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
231 | } else if (cpu_is_omap343x()) { | 271 | } else if (cpu_is_omap343x()) { |
232 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | 272 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; |
233 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; | 273 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; |
274 | omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = | ||
275 | omap_mcbsp_set_threshold; | ||
276 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | ||
277 | if (omap_mcbsp_get_dma_op_mode(bus_id) == | ||
278 | MCBSP_DMA_MODE_THRESHOLD) | ||
279 | sync_mode = OMAP_DMA_SYNC_FRAME; | ||
234 | } else { | 280 | } else { |
235 | return -ENODEV; | 281 | return -ENODEV; |
236 | } | 282 | } |
@@ -238,6 +284,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
238 | substream->stream ? "Audio Capture" : "Audio Playback"; | 284 | substream->stream ? "Audio Capture" : "Audio Playback"; |
239 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; | 285 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; |
240 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; | 286 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; |
287 | omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; | ||
241 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; | 288 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; |
242 | 289 | ||
243 | if (mcbsp_data->configured) { | 290 | if (mcbsp_data->configured) { |
@@ -321,11 +368,14 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
321 | /* Generic McBSP register settings */ | 368 | /* Generic McBSP register settings */ |
322 | regs->spcr2 |= XINTM(3) | FREE; | 369 | regs->spcr2 |= XINTM(3) | FREE; |
323 | regs->spcr1 |= RINTM(3); | 370 | regs->spcr1 |= RINTM(3); |
324 | regs->rcr2 |= RFIG; | 371 | /* RFIG and XFIG are not defined in 34xx */ |
325 | regs->xcr2 |= XFIG; | 372 | if (!cpu_is_omap34xx()) { |
373 | regs->rcr2 |= RFIG; | ||
374 | regs->xcr2 |= XFIG; | ||
375 | } | ||
326 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { | 376 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { |
327 | regs->xccr = DXENDLY(1) | XDMAEN; | 377 | regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; |
328 | regs->rccr = RFULL_CYCLE | RDMAEN; | 378 | regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; |
329 | } | 379 | } |
330 | 380 | ||
331 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 381 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
@@ -462,6 +512,40 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
462 | return 0; | 512 | return 0; |
463 | } | 513 | } |
464 | 514 | ||
515 | static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data, | ||
516 | int clk_id) | ||
517 | { | ||
518 | int sel_bit, set = 0; | ||
519 | u16 reg = OMAP2_CONTROL_DEVCONF0; | ||
520 | |||
521 | if (cpu_class_is_omap1()) | ||
522 | return -EINVAL; /* TODO: Can this be implemented for OMAP1? */ | ||
523 | if (mcbsp_data->bus_id != 0) | ||
524 | return -EINVAL; | ||
525 | |||
526 | switch (clk_id) { | ||
527 | case OMAP_MCBSP_CLKR_SRC_CLKX: | ||
528 | set = 1; | ||
529 | case OMAP_MCBSP_CLKR_SRC_CLKR: | ||
530 | sel_bit = 3; | ||
531 | break; | ||
532 | case OMAP_MCBSP_FSR_SRC_FSX: | ||
533 | set = 1; | ||
534 | case OMAP_MCBSP_FSR_SRC_FSR: | ||
535 | sel_bit = 4; | ||
536 | break; | ||
537 | default: | ||
538 | return -EINVAL; | ||
539 | } | ||
540 | |||
541 | if (set) | ||
542 | omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg); | ||
543 | else | ||
544 | omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
465 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | 549 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
466 | int clk_id, unsigned int freq, | 550 | int clk_id, unsigned int freq, |
467 | int dir) | 551 | int dir) |
@@ -484,6 +568,13 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
484 | case OMAP_MCBSP_SYSCLK_CLKR_EXT: | 568 | case OMAP_MCBSP_SYSCLK_CLKR_EXT: |
485 | regs->pcr0 |= SCLKME; | 569 | regs->pcr0 |= SCLKME; |
486 | break; | 570 | break; |
571 | |||
572 | case OMAP_MCBSP_CLKR_SRC_CLKR: | ||
573 | case OMAP_MCBSP_CLKR_SRC_CLKX: | ||
574 | case OMAP_MCBSP_FSR_SRC_FSR: | ||
575 | case OMAP_MCBSP_FSR_SRC_FSX: | ||
576 | err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id); | ||
577 | break; | ||
487 | default: | 578 | default: |
488 | err = -ENODEV; | 579 | err = -ENODEV; |
489 | } | 580 | } |