Title: [8681] trunk/sound/soc: Add PLL setting.
Revision
8681
Author
adamliyi
Date
2010-04-29 05:09:00 -0400 (Thu, 29 Apr 2010)

Log Message

Add PLL setting.
Issue: "arecord -r 44100 -f S16_LE -c 2 | aplay" causes underrun.

Modified Paths

Diff

Modified: trunk/sound/soc/blackfin/bf5xx-adav80x.c (8680 => 8681)


--- trunk/sound/soc/blackfin/bf5xx-adav80x.c	2010-04-29 08:43:02 UTC (rev 8680)
+++ trunk/sound/soc/blackfin/bf5xx-adav80x.c	2010-04-29 09:09:00 UTC (rev 8681)
@@ -57,23 +57,13 @@
 
 	pr_debug("%s rate %d format %x\n", __func__, params_rate(params),
 		params_format(params));
-	/*
-	 * If you are using a crystal source which frequency is not 12MHz
-	 * then modify the below case statement with frequency of the crystal.
-	 *
-	 * If you are using the SPORT to generate clocking then this is
-	 * where to do it.
-	 */
 
 	switch (params_rate(params)) {
-	case 8000:
-	case 16000:
+	case 32000:
+	case 44100:
 	case 48000:
 	case 96000:
-	case 11025:
-	case 22050:
-	case 44100:
-		clk = 12000000;
+		clk = params_rate(params);
 		break;
 	}
 
@@ -91,12 +81,17 @@
 		SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
 	if (ret < 0)
 		return ret;
-/*
-	ret = snd_soc_dai_set_sysclk(codec_dai, ADAV80X_SYSCLK, clk,
-		SND_SOC_CLOCK_IN);
+
+	/* For the ADAV80X evaluation board, use the on board crystal
+	   as XIN, and use XIN as source for PLL1 */
+	ret = snd_soc_dai_set_pll(codec_dai, ADAV80X_CLK_PLL1,
+			ADAV80X_CLK_XIN, 27000000, clk);
+
+	/* If you want to use XIN as clock source */
+	/* ret = snd_soc_dai_set_pll(codec_dai, 0, ADAV80X_CLK_XIN,
+		27000000, 0); */
 	if (ret < 0)
 		return ret;
-*/
 	return 0;
 }
 

Modified: trunk/sound/soc/codecs/adav80x.c (8680 => 8681)


--- trunk/sound/soc/codecs/adav80x.c	2010-04-29 08:43:02 UTC (rev 8680)
+++ trunk/sound/soc/codecs/adav80x.c	2010-04-29 09:09:00 UTC (rev 8681)
@@ -25,6 +25,7 @@
 struct adav80x_priv {
 	struct snd_soc_codec codec;
 	u16 reg_cache[ADAV80X_NUM_REGS];
+	int clk_src; /* clock source for ADC, DAC and internal clock */
 };
 
 static struct snd_soc_codec *adav80x_codec;
@@ -135,15 +136,66 @@
 	return 0;
 }
 
+static int adav80x_set_adc_clock(struct snd_soc_codec *codec,
+		int clk_id, unsigned int sample_rate)
+{
+	int reg;
+
+	if (clk_id == ADAV80X_CLK_PLL1) {
+		/* ADC assumes that the MCLK ratre is 256 times the sample rate.
+		   We also assumes PLL1 clock rate to be (256 * Fs),
+		   So set ADC MCLK divider to be 1 */
+
+		reg = snd_soc_read(codec, ADAV80X_ADC_CTRL1);
+		/* ADC Modulator clock is 6.144MHz Max,
+		   need to set devidor properly */
+		if (sample_rate == 96000)
+			reg |= 0x80;
+		else if (sample_rate == 48000)
+			reg &= 0x7F;
+		else
+			/* Unsupported sample rate */
+			return -1;
+
+		snd_soc_write(codec, ADAV80X_ADC_CTRL1, reg);
+	}
+
+	return 0;
+}
+
+static int adav80x_set_dac_clock(struct snd_soc_codec *codec,
+		int clk_id, unsigned int sample_rate)
+{
+	int reg;
+
+	if (clk_id == ADAV80X_CLK_PLL1) {
+		/* PLL1 clock rate is assumed to be 256 * Fs */
+
+		reg = snd_soc_read(codec, ADAV80X_DAC_CTRL2);
+		if (sample_rate == 96000)
+			/* Set the MCLK divider to be MCLK/2,
+			   and MCLK = 128 * Fs */
+			reg |= 0x24;
+		else
+			reg &= 0x11;
+
+		snd_soc_write(codec, ADAV80X_DAC_CTRL2, reg);
+	}
+
+	return 0;
+}
+
 static int adav80x_hw_params(struct snd_pcm_substream *substream,
 		struct snd_pcm_hw_params *params,
 		struct snd_soc_dai *dai)
 {
 	int word_len = 0;
+	int rate = params_rate(params);
 
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
+	struct adav80x_priv *adav80x = codec->private_data;
 
 	/* bit size */
 	switch (params_format(params)) {
@@ -167,6 +219,14 @@
 	/* Record Port Control */
 	snd_soc_update_bits(codec, ADAV80X_REC_CTRL, 0x3<<2, word_len<<2);
 
+	/* Set up clock */
+	if (adav80x->clk_src == ADAV80X_CLK_PLL1) {
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			adav80x_set_dac_clock(codec, ADAV80X_CLK_PLL1, rate);
+		else
+			adav80x_set_adc_clock(codec, ADAV80X_CLK_PLL1, rate);
+	}
+
 	return 0;
 }
 
@@ -198,10 +258,86 @@
 	return 0;
 }
 
+
+static int adav80x_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
+		int source, unsigned int freq_in, unsigned int freq_out)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct adav80x_priv *adav80x = codec->private_data;
+	int reg = 0;
+
+	/* For now, we only enable PLL1 with XIN as source */
+	if (source != ADAV80X_CLK_XIN)
+		return -1;
+
+	if (freq_in && freq_out) {
+		/* XIN - assumes 27MHz */
+		if (freq_in != 27000000)
+			return -1;
+
+		if (pll_id != ADAV80X_CLK_PLL1)
+			return -1;
+
+		/* freq_out = sample_rate * 256 */
+		switch (freq_out) {
+		case 32000:
+			reg = 0x8;
+			break;
+		case 44100:
+			reg = 0xC;
+			break;
+		case 48000:
+			reg = 0x0;
+			break;
+		case 64000:
+			reg = 0x9;
+			break;
+		case 88200:
+			reg = 0xD;
+			break;
+		case 96000:
+			reg = 0x1;
+			break;
+		}
+
+		/* Set PLL1 clock */
+		snd_soc_write(codec, ADAV80X_PLL_CTRL2, reg);
+
+		if (adav80x->clk_src == ADAV80X_CLK_PLL1)
+			return 0;
+		else
+			adav80x->clk_src = ADAV80X_CLK_PLL1;
+
+		/* select XIN as PLL1 clock source */
+		snd_soc_write(codec, ADAV80X_PLL_CLK_SRC, 0x0);
+		/* set PLL1 as clock source for internal clock, DAC, ADC */
+		snd_soc_write(codec, ADAV80X_ICLK_CTRL1, 0x4A);
+		snd_soc_write(codec, ADAV80X_ICLK_CTRL2, 0x10);
+		/* Power on PLL1, power down PLL2, power on XTAL */
+		snd_soc_write(codec, ADAV80X_PLL_CTRL1, 0x8);
+
+	} else	{
+		if (adav80x->clk_src == ADAV80X_CLK_XIN)
+			return 0;
+		else
+			adav80x->clk_src = ADAV80X_CLK_XIN;
+
+		/* Turn off PLL, power on XTAL */
+		snd_soc_write(codec, ADAV80X_PLL_CTRL1, 0xC);
+
+		/* DAC, ADC, ICLK clock source - XIN */
+		snd_soc_write(codec, ADAV80X_ICLK_CTRL1, 0x0);
+		snd_soc_write(codec, ADAV80X_ICLK_CTRL2, 0x0);
+	}
+
+	return 0;
+}
+
 static struct snd_soc_dai_ops adav80x_dai_ops = {
 	.hw_params = adav80x_hw_params,
 	.set_fmt = adav80x_set_dai_fmt,
 	.digital_mute = adav80x_mute,
+	.set_pll = adav80x_set_dai_pll,
 };
 
 /* codec DAI instance */
@@ -212,7 +348,8 @@
 		.stream_name = "Playback",
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100 |
+				SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_96000,
 		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
@@ -220,7 +357,7 @@
 		.stream_name = "Capture",
 		.channels_min = 2,
 		.channels_max = 2,
-		.rates = SNDRV_PCM_RATE_48000,
+		.rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000,
 		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
 			SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
 	},
@@ -337,13 +474,6 @@
 
 	/* default setting for adav80x */
 
-	/* These should be set on board level? */
-	/* DAC, ADC, ICLK clock source - XIN */
-	snd_soc_write(codec, ADAV80X_ICLK_CTRL1, 0x0);
-	snd_soc_write(codec, ADAV80X_ICLK_CTRL2, 0x0);
-
-	/* Power up XTAL oscillator */
-	snd_soc_write(codec, ADAV80X_PLL_CTRL1, 0xC);
 	/* Power down SYSCLK output, power down S/PDIF receiver */
 	snd_soc_write(codec, ADAV80X_PLL_OUTE, 0x27);
 
@@ -359,7 +489,7 @@
 	snd_soc_write(codec, ADAV80X_GDELAY_MUTE, 0x80);
 
 	/* DAC: de-emphasis: none, MCLCK divider: 1, MCLK=256xFs */
-	snd_soc_write(codec, ADAV80X_DAC_CTRL2, 0x0);
+	/* snd_soc_write(codec, ADAV80X_DAC_CTRL2, 0x0); */
 	/* Disable DAC zero flag */
 	snd_soc_write(codec, ADAV80X_DAC_CTRL3, 0x6);
 	/* DAC: volume */
@@ -367,9 +497,9 @@
 	snd_soc_write(codec, ADAV80X_DAC_R_VOL, 0xFF);
 
 	/* ADC: power up, unmute adc channles */
-	snd_soc_write(codec, ADAV80X_ADC_CTRL1, 0x0);
+	/* snd_soc_write(codec, ADAV80X_ADC_CTRL1, 0x0); */
 	/* MCLCK divider: 1 */
-	snd_soc_write(codec, ADAV80X_ADC_CTRL2, 0x0);
+	/* snd_soc_write(codec, ADAV80X_ADC_CTRL2, 0x0); */
 	/* ADC: volumn */
 	snd_soc_write(codec, ADAV80X_ADC_L_VOL, 0xFF);
 	snd_soc_write(codec, ADAV80X_ADC_R_VOL, 0xFF);

Modified: trunk/sound/soc/codecs/adav80x.h (8680 => 8681)


--- trunk/sound/soc/codecs/adav80x.h	2010-04-29 08:43:02 UTC (rev 8680)
+++ trunk/sound/soc/codecs/adav80x.h	2010-04-29 09:09:00 UTC (rev 8681)
@@ -1,6 +1,15 @@
 extern struct snd_soc_dai adav80x_dai;
 extern struct snd_soc_codec_device soc_codec_dev_adav80x;
 
+/* Clock source */
+#define ADAV80X_CLK_XIN		1
+#define ADAV80X_CLK_PLL1	2
+#define ADAV80X_CLK_PLL2	3
+#define ADAV80X_CLK_INTERNAL1	4
+#define ADAV80X_CLK_INTERNAL2	5
+#define ADAV80X_CLK_MCLKI	6
+
+
 #if (CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /* ADAV80X I2C interface requires left-shifting reg addr for 1-bit */
 #define ADAV80X_NUM_REGS (0x7E<<1)
@@ -36,6 +45,7 @@
 #define ADAV80X_PLL_CTRL2	(0x75<<1)
 #define ADAV80X_ICLK_CTRL1	(0x76<<1)
 #define ADAV80X_ICLK_CTRL2	(0x77<<1)
+#define ADAV80X_PLL_CLK_SRC	(0x78<<1)
 
 #define ADAV80X_PLL_OUTE	(0x7A<<1)
 #define ADAV80X_ALC_CTRL1	(0x7B<<1)
@@ -75,6 +85,7 @@
 #define ADAV80X_PLL_CTRL2	0x75
 #define ADAV80X_ICLK_CTRL1	0x76
 #define ADAV80X_ICLK_CTRL2	0x77
+#define ADAV80X_PLL_CLK_SRC	0x78
 
 #define ADAV80X_PLL_OUTE	0x7A
 #define ADAV80X_ALC_CTRL1	0x7B
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
https://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to