[alsa-devel] [PATCH 2/3] ASoC: pxa-ssp.c, Automatically set TDM when needed

Daniel Ribeiro drwyrm at gmail.com
Fri Aug 14 18:17:41 CEST 2009


Hi, sorry for the delay on replying to this thread, busy with other
stuff. :)

Em Qua, 2009-08-12 às 20:17 +0200, Daniel Mack escreveu:
> Again, to summarize what this is all about - what I need the code to
> produce is the following output:
> 
> 	- syncronous LRCLK
> 	- 64fs on I2SCLK
> 	- I2S data on the first 16bits of each LRCLK edge
> 	-> http://caiaq.de/download/tmp/2.png
> 
> So I applied all three patches and added the following call to my board
> support code:
> 
> 	snd_soc_dai_set_tdm_slot(cpu_dai, 3, 3, 2, 16);
> 
> Which translates into "give me 2 slots with 16 bits each, and distribute
> them over the timeline as a 0-1-0-1 pattern". Which is exactly what I
> need, right?

No. in an ideal world, set_tdm_slot(3, 3, 2, 16) shoud give you 2x16
bits slots, on a 1-1 timeline, and shouldn't be a valid network mode
configuration, in this case, one should use a frame width of 32bits and
_not_ use network mode.

0-1-0-1 should be 4 slots, with slots 2 and 4 active, but I think that
what you want is 1-0-1-0 = set_tdm_slot(5, 5, 4, 16). But... See below.

> But unfortunately, the code didn't make the SSP port do that. I ended up
> having a asynchronous clock and the data somewhere where I wouldn't have
> expected them: http://caiaq.de/download/tmp/1.png

I think that the source of the problem is that we can't assert SFRM past
the end of the first slot, and DMYSTOP changes the slot_width on the
wire.

Consider that PXA is _slave_ of SFRM: (SFRMDIR=1)

* SFRMWDTH is ignored.
* Only one edge (set by SFRMP) is considered.


And when PXA is _master_ of SFRM: (SFRMDIR=0)

* SFRMWDTH is needed for I2S.
* SFRMWDTH can't be asserted past the end of DMYSTOP.
* DMYSTOP changes the slot width, as it generates extra cycles after the
last bit of data.
* DMYSTOP only changes the _active_ slots width. (this is what causes
async SFRM).
* DMYSTOP is restricted to 0-3 on PXA2XX
* DMYSTOP must be cleared in network mode, or when FSRT is set.


We want to write 2x16bit samples with 1-0-1-0 pattern for I2S, so we
can:

* set_tdm_slot(5, 5, 4, 16) if pxa is slave of SFRM.
* use SFRMWDTH(16) | DMYSTOP(16) if pxa is master of SFRM. (pxa3 only)
* use DMYSTOP(16) if pxa is slave of SFRM. (pxa3 only)


> I did some minor modifications to the patches 2/3 and 3/3 which made it
> work for me eventually - find them inline.
> 
> Not sure whether I got the theory about the API right, and of course I
> didn't test on any other hardware than the one I have.
> 
> 

> > -	cpu_dai->dma_data = ssp_get_dma_params(ssp,
> > -			((chn == 2) && (ttsa != 1)) || (width == 32),
> > +	cpu_dai->dma_data = ssp_get_dma_params(ssp, slot_width > 16,
> >  			substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
> 
> The condition for the width4 parameter needs to be
> (slot_width * slots) > 16 for me. With that parameter set to 0, audio
> plays at half speed on my system.

Consider that you have real network mode, and you are using 2 slots of
16 bit mono audio. You want to ignore 16bit for each 16bit of data. ie,
only one channel active. You really don't want 32bit DMA in this case.

I agree that this should be (slot_width * number_of_active_slots) > 16
tough.

> And in patch 3/3,
> 

> > +			sspsp |= SSPSP_DMYSTOP(
> > +					(slot_width * slots) / 2 - width - 1);
> > +			sspsp |= SSPSP_SFRMWDTH((slot_width * slots) / 2);
> 
> These two calculations are wrong my case. What works here is
> 
> 	sspsp |= SSPSP_DMYSTOP(
> 			(slot_width * slots * chn) / 2 - width - 1);
> 	sspsp |= SSPSP_SFRMWDTH((slot_width * slots * chn) / 2);
> 
> ... which is another multiplication by factor 2. But I'm not sure if I
> got the wrong variable with value 2 :)

DMYSTOP itself should be accounted for slot_width, but this will only
work if all slots are active otherwise you will get asynchronous SFRM.
Something like:

/*
 * If the user did not use network mode, we assume the codec
 * is I2S compliant.
 */
if (frame_width > 0) {
	sspsp |= SSPSP_SFRMWDTH(frame_width / 2);
	sspsp |= SSPSP_FSRT;
} else {
	if (sscr0 & SSCR0_SFRMDIR) {
		/* pxa slave, FSRT is enough */
		sspsp |= SSPSP_FSRT;
	} else {
		/* pxa master */
		int slots = ((sscr0 & SSCR0_SlotsPerFrm(8)) >> 24) + 1;

		/* PXA2XX doesn't support DMYSTOP > 3 */
		if (!cpu_is_pxa3xx())
			return -EINVAL;
		/* 
		 * We need all slots active, otherwise DMYSTOP causes
		 * asynchronous SFRM as it only appends bit cycles after
		 * active slots.
		 */
		if (ssta != (1 << slots) - 1)
			return -EINVAL;

		/* slot width on the wire is doubled by DMYSTOP */
		sspsp |= SSPSP_DMYSTRT(1);
		sspsp |= SSPSP_DMYSTOP(slot_width * slots - width - 1);
		sspsp |= SSPSP_SFRMWDTH(slot_width * slots);


This should be able to deal with I2S when pxa is slave, on both pxa2xx
and pxa3xx, with set_tdm_slot(5, 5, 4, 16).

Or when pxa is master, on pxa3xx only, with set_tdm_slot(3, 3, 2, 16).
This still violates the "DMYSTOP must be clear on network mode" rule,
but as all slots are active its not really network mode. And it seems to
work for you, so... ;)
		

-- 
Daniel Ribeiro
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Esta =?ISO-8859-1?Q?=E9?= uma parte de mensagem
 assinada digitalmente
Url : http://mailman.alsa-project.org/pipermail/alsa-devel/attachments/20090814/71bbaa6f/attachment.sig 


More information about the Alsa-devel mailing list