[alsa-devel] ASOC, master clock direction

Jon Smirl jonsmirl at gmail.com
Fri Jul 18 21:44:37 CEST 2008


On 7/18/08, Jon Smirl <jonsmirl at gmail.com> wrote:
> The MPC5200 has three clock configurations
>
>  1) Clock out, normal master mode
>  2) Clock in, normal slave mode
>  3) Something Freescale calls cellphone slave but it is more like clock
>  distribution.
>
>  In cellslave mode one i2s port is in normal slave mode. The clock from
>  this port is used to drive up to three other i2s ports in master mode.
>
>  I have two choices for set_sysclk:
>  #define SND_SOC_CLOCK_IN        0
>  #define SND_SOC_CLOCK_OUT       1
>
>  When the clock frequency changes I need to notify the i2s drivers for
>  the dependent channels. Do we need a third choice,
>  SND_SOC_CLOCK_SLAVE? Alternatively I can use another clock id value.

I can implement it like this, in cellslave mode I just record the
frequency, CLOCK_OUT not in cellslave mode needs to set up the
internal MPC clock generation (which can't make accurate audio
clocks).

static int psc_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
			      int clk_id, unsigned int freq, int dir)
{
	struct psc_i2s *psc_i2s = cpu_dai->private_data;
	dev_dbg(psc_i2s->dev, "psc_i2s_set_sysclk(cpu_dai=%p, freq=%ui, dir=%i)\n",
				cpu_dai, freq, dir);
	switch (dir) {
	case SND_SOC_CLOCK_IN:
		return 0;
	case SND_SOC_CLOCK_OUT:
	default:
		if (!(psc_i2s->sicr & MPC52xx_PSC_SICR_CELLSLAVE)) {
			/* implement me */
			/* compute and set the needed dividers for the internal clock */
			return -EINVAL;
		}
		psc_i2s->sysclk = freq;
		return -EINVAL;
	}
}


static int psc_i2s_hw_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
	struct psc_i2s *psc_i2s = rtd->dai->cpu_dai->private_data;
	u32 sicr, rate, bits, bitblk, err, wordclk;

	dev_dbg(psc_i2s->dev, "%s(substream=%p) p_size=%i p_bytes=%i"
		" periods=%i buffer_size=%i  buffer_bytes=%i\n",
		__FUNCTION__, substream, params_period_size(params),
		params_period_bytes(params), params_periods(params),
		params_buffer_size(params), params_buffer_bytes(params));

	sicr = psc_i2s->sicr;
	switch (params_format(params)) {
	 case SNDRV_PCM_FORMAT_S8:
		sicr |= MPC52xx_PSC_SICR_SIM_CODEC_8;
		bits = 8;
		break;
	 case SNDRV_PCM_FORMAT_S16_BE:
		sicr |= MPC52xx_PSC_SICR_SIM_CODEC_16;
		bits = 16;
		break;
	 case SNDRV_PCM_FORMAT_S24_BE:
		sicr |= MPC52xx_PSC_SICR_SIM_CODEC_24;
		bits = 24;
		break;
	 case SNDRV_PCM_FORMAT_S32_BE:
		sicr |= MPC52xx_PSC_SICR_SIM_CODEC_32;
		bits = 32;
		break;
	 default:
		dev_dbg(psc_i2s->dev, "invalid format\n");
		return -EINVAL;
	}
	out_be32(&psc_i2s->psc_regs->sicr, sicr);
	
	if (psc_i2s->sysclk) {
		switch (params_rate(params)) {
		case SNDRV_PCM_RATE_5512: rate = 5512; break;
		case SNDRV_PCM_RATE_8000: rate = 8000; break;
		case SNDRV_PCM_RATE_11025: rate = 11025; break;
		case SNDRV_PCM_RATE_16000: rate = 16000; break;
		case SNDRV_PCM_RATE_22050: rate = 22050; break;
		case SNDRV_PCM_RATE_32000: rate = 32000; break;
		case SNDRV_PCM_RATE_44100: rate = 44100; break;
		case SNDRV_PCM_RATE_48000: rate = 48000; break;
		case SNDRV_PCM_RATE_64000: rate = 64000; break;
		case SNDRV_PCM_RATE_88200: rate = 88200; break;
		case SNDRV_PCM_RATE_96000: rate = 96000; break;
		case SNDRV_PCM_RATE_176400: rate = 176400; break;
		case SNDRV_PCM_RATE_192000: rate = 192000; break;
		 default:
			dev_dbg(psc_i2s->dev, "invalid format\n");
			return -EINVAL;
		}
		bitclk = psc_i2s->sysclk / rate;
		wordclk = bitclk / bits;
		out_be32(&psc_i2s->psc_regs->ccr, (bitclk - 1) << 24 | (wordclk << 16);
	}

	//rc = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
	//if (rc) {
	//	dev_err(psc_i2s->dev, "could not allocate dma buffer\n");
	//	return rc;
	//}

	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);

	return 0;
}



>
>
>  --
>  Jon Smirl
>  jonsmirl at gmail.com
>


-- 
Jon Smirl
jonsmirl at gmail.com


More information about the Alsa-devel mailing list