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.c175
1 files changed, 125 insertions, 50 deletions
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 6f44cb4d30b8..86f213905e2c 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -59,6 +59,7 @@ struct omap_mcbsp_data {
59 int configured; 59 int configured;
60 unsigned int in_freq; 60 unsigned int in_freq;
61 int clk_div; 61 int clk_div;
62 int wlen;
62}; 63};
63 64
64#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id) 65#define to_mcbsp(priv) container_of((priv), struct omap_mcbsp_data, bus_id)
@@ -154,20 +155,51 @@ static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream)
154 struct snd_soc_pcm_runtime *rtd = substream->private_data; 155 struct snd_soc_pcm_runtime *rtd = substream->private_data;
155 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 156 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
156 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); 157 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
158 struct omap_pcm_dma_data *dma_data;
157 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); 159 int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id);
158 int samples; 160 int words;
161
162 dma_data = snd_soc_dai_get_dma_data(rtd->dai->cpu_dai, substream);
159 163
160 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ 164 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
161 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) 165 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
162 samples = snd_pcm_lib_period_bytes(substream) >> 1; 166 /*
167 * Configure McBSP threshold based on either:
168 * packet_size, when the sDMA is in packet mode, or
169 * based on the period size.
170 */
171 if (dma_data->packet_size)
172 words = dma_data->packet_size;
173 else
174 words = snd_pcm_lib_period_bytes(substream) /
175 (mcbsp_data->wlen / 8);
163 else 176 else
164 samples = 1; 177 words = 1;
165 178
166 /* Configure McBSP internal buffer usage */ 179 /* Configure McBSP internal buffer usage */
167 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 180 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
168 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); 181 omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, words);
169 else 182 else
170 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); 183 omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, words);
184}
185
186static int omap_mcbsp_hwrule_min_buffersize(struct snd_pcm_hw_params *params,
187 struct snd_pcm_hw_rule *rule)
188{
189 struct snd_interval *buffer_size = hw_param_interval(params,
190 SNDRV_PCM_HW_PARAM_BUFFER_SIZE);
191 struct snd_interval *channels = hw_param_interval(params,
192 SNDRV_PCM_HW_PARAM_CHANNELS);
193 struct omap_mcbsp_data *mcbsp_data = rule->private;
194 struct snd_interval frames;
195 int size;
196
197 snd_interval_any(&frames);
198 size = omap_mcbsp_get_fifo_size(mcbsp_data->bus_id);
199
200 frames.min = size / channels->min;
201 frames.integer = 1;
202 return snd_interval_refine(buffer_size, &frames);
171} 203}
172 204
173static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, 205static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
@@ -182,33 +214,35 @@ static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream,
182 if (!cpu_dai->active) 214 if (!cpu_dai->active)
183 err = omap_mcbsp_request(bus_id); 215 err = omap_mcbsp_request(bus_id);
184 216
217 /*
218 * OMAP3 McBSP FIFO is word structured.
219 * McBSP2 has 1024 + 256 = 1280 word long buffer,
220 * McBSP1,3,4,5 has 128 word long buffer
221 * This means that the size of the FIFO depends on the sample format.
222 * For example on McBSP3:
223 * 16bit samples: size is 128 * 2 = 256 bytes
224 * 32bit samples: size is 128 * 4 = 512 bytes
225 * It is simpler to place constraint for buffer and period based on
226 * channels.
227 * McBSP3 as example again (16 or 32 bit samples):
228 * 1 channel (mono): size is 128 frames (128 words)
229 * 2 channels (stereo): size is 128 / 2 = 64 frames (2 * 64 words)
230 * 4 channels: size is 128 / 4 = 32 frames (4 * 32 words)
231 */
185 if (cpu_is_omap343x()) { 232 if (cpu_is_omap343x()) {
186 int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id);
187 int max_period;
188
189 /* 233 /*
190 * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. 234 * Rule for the buffer size. We should not allow
191 * Set constraint for minimum buffer size to the same than FIFO 235 * smaller buffer than the FIFO size to avoid underruns
192 * size in order to avoid underruns in playback startup because 236 */
193 * HW is keeping the DMA request active until FIFO is filled. 237 snd_pcm_hw_rule_add(substream->runtime, 0,
194 */ 238 SNDRV_PCM_HW_PARAM_CHANNELS,
195 if (bus_id == 1) 239 omap_mcbsp_hwrule_min_buffersize,
196 snd_pcm_hw_constraint_minmax(substream->runtime, 240 mcbsp_data,
197 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 241 SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
198 4096, UINT_MAX); 242
199 243 /* Make sure, that the period size is always even */
200 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 244 snd_pcm_hw_constraint_step(substream->runtime, 0,
201 max_period = omap_mcbsp_get_max_tx_threshold(bus_id); 245 SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
202 else
203 max_period = omap_mcbsp_get_max_rx_threshold(bus_id);
204
205 max_period++;
206 max_period <<= 1;
207
208 if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD)
209 snd_pcm_hw_constraint_minmax(substream->runtime,
210 SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
211 32, max_period);
212 } 246 }
213 247
214 return err; 248 return err;
@@ -289,11 +323,14 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
289 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 323 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
290 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); 324 struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
291 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; 325 struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
292 int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; 326 struct omap_pcm_dma_data *dma_data;
327 int dma, bus_id = mcbsp_data->bus_id;
293 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; 328 int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT;
329 int pkt_size = 0;
294 unsigned long port; 330 unsigned long port;
295 unsigned int format, div, framesize, master; 331 unsigned int format, div, framesize, master;
296 332
333 dma_data = &omap_mcbsp_dai_dma_params[cpu_dai->id][substream->stream];
297 if (cpu_class_is_omap1()) { 334 if (cpu_class_is_omap1()) {
298 dma = omap1_dma_reqs[bus_id][substream->stream]; 335 dma = omap1_dma_reqs[bus_id][substream->stream];
299 port = omap1_mcbsp_port[bus_id][substream->stream]; 336 port = omap1_mcbsp_port[bus_id][substream->stream];
@@ -306,35 +343,74 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
306 } else if (cpu_is_omap343x()) { 343 } else if (cpu_is_omap343x()) {
307 dma = omap24xx_dma_reqs[bus_id][substream->stream]; 344 dma = omap24xx_dma_reqs[bus_id][substream->stream];
308 port = omap34xx_mcbsp_port[bus_id][substream->stream]; 345 port = omap34xx_mcbsp_port[bus_id][substream->stream];
309 omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold =
310 omap_mcbsp_set_threshold;
311 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
312 if (omap_mcbsp_get_dma_op_mode(bus_id) ==
313 MCBSP_DMA_MODE_THRESHOLD)
314 sync_mode = OMAP_DMA_SYNC_FRAME;
315 } else { 346 } else {
316 return -ENODEV; 347 return -ENODEV;
317 } 348 }
318 omap_mcbsp_dai_dma_params[id][substream->stream].name =
319 substream->stream ? "Audio Capture" : "Audio Playback";
320 omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
321 omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
322 omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode;
323 switch (params_format(params)) { 349 switch (params_format(params)) {
324 case SNDRV_PCM_FORMAT_S16_LE: 350 case SNDRV_PCM_FORMAT_S16_LE:
325 omap_mcbsp_dai_dma_params[id][substream->stream].data_type = 351 dma_data->data_type = OMAP_DMA_DATA_TYPE_S16;
326 OMAP_DMA_DATA_TYPE_S16; 352 wlen = 16;
327 break; 353 break;
328 case SNDRV_PCM_FORMAT_S32_LE: 354 case SNDRV_PCM_FORMAT_S32_LE:
329 omap_mcbsp_dai_dma_params[id][substream->stream].data_type = 355 dma_data->data_type = OMAP_DMA_DATA_TYPE_S32;
330 OMAP_DMA_DATA_TYPE_S32; 356 wlen = 32;
331 break; 357 break;
332 default: 358 default:
333 return -EINVAL; 359 return -EINVAL;
334 } 360 }
361 if (cpu_is_omap343x()) {
362 dma_data->set_threshold = omap_mcbsp_set_threshold;
363 /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */
364 if (omap_mcbsp_get_dma_op_mode(bus_id) ==
365 MCBSP_DMA_MODE_THRESHOLD) {
366 int period_words, max_thrsh;
367
368 period_words = params_period_bytes(params) / (wlen / 8);
369 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
370 max_thrsh = omap_mcbsp_get_max_tx_threshold(
371 mcbsp_data->bus_id);
372 else
373 max_thrsh = omap_mcbsp_get_max_rx_threshold(
374 mcbsp_data->bus_id);
375 /*
376 * If the period contains less or equal number of words,
377 * we are using the original threshold mode setup:
378 * McBSP threshold = sDMA frame size = period_size
379 * Otherwise we switch to sDMA packet mode:
380 * McBSP threshold = sDMA packet size
381 * sDMA frame size = period size
382 */
383 if (period_words > max_thrsh) {
384 int divider = 0;
385
386 /*
387 * Look for the biggest threshold value, which
388 * divides the period size evenly.
389 */
390 divider = period_words / max_thrsh;
391 if (period_words % max_thrsh)
392 divider++;
393 while (period_words % divider &&
394 divider < period_words)
395 divider++;
396 if (divider == period_words)
397 return -EINVAL;
398
399 pkt_size = period_words / divider;
400 sync_mode = OMAP_DMA_SYNC_PACKET;
401 } else {
402 sync_mode = OMAP_DMA_SYNC_FRAME;
403 }
404 }
405 }
335 406
336 snd_soc_dai_set_dma_data(cpu_dai, substream, 407 dma_data->name = substream->stream ? "Audio Capture" : "Audio Playback";
337 &omap_mcbsp_dai_dma_params[id][substream->stream]); 408 dma_data->dma_req = dma;
409 dma_data->port_addr = port;
410 dma_data->sync_mode = sync_mode;
411 dma_data->packet_size = pkt_size;
412
413 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
338 414
339 if (mcbsp_data->configured) { 415 if (mcbsp_data->configured) {
340 /* McBSP already configured by another stream */ 416 /* McBSP already configured by another stream */
@@ -360,7 +436,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
360 switch (params_format(params)) { 436 switch (params_format(params)) {
361 case SNDRV_PCM_FORMAT_S16_LE: 437 case SNDRV_PCM_FORMAT_S16_LE:
362 /* Set word lengths */ 438 /* Set word lengths */
363 wlen = 16;
364 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16); 439 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_16);
365 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16); 440 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_16);
366 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16); 441 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_16);
@@ -368,7 +443,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
368 break; 443 break;
369 case SNDRV_PCM_FORMAT_S32_LE: 444 case SNDRV_PCM_FORMAT_S32_LE:
370 /* Set word lengths */ 445 /* Set word lengths */
371 wlen = 32;
372 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32); 446 regs->rcr2 |= RWDLEN2(OMAP_MCBSP_WORD_32);
373 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32); 447 regs->rcr1 |= RWDLEN1(OMAP_MCBSP_WORD_32);
374 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32); 448 regs->xcr2 |= XWDLEN2(OMAP_MCBSP_WORD_32);
@@ -409,6 +483,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
409 } 483 }
410 484
411 omap_mcbsp_config(bus_id, &mcbsp_data->regs); 485 omap_mcbsp_config(bus_id, &mcbsp_data->regs);
486 mcbsp_data->wlen = wlen;
412 mcbsp_data->configured = 1; 487 mcbsp_data->configured = 1;
413 488
414 return 0; 489 return 0;