aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/omap/omap-mcbsp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/omap/omap-mcbsp.c')
-rw-r--r--sound/soc/omap/omap-mcbsp.c123
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] = {
139static const unsigned long omap34xx_mcbsp_port[][2] = {}; 139static const unsigned long omap34xx_mcbsp_port[][2] = {};
140#endif 140#endif
141 141
142static 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
142static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, 163static 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
515static 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
465static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, 549static 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 }