summary refs log tree commit diff
path: root/sound/soc/codecs/da7210.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/codecs/da7210.c')
-rw-r--r--sound/soc/codecs/da7210.c157
1 files changed, 134 insertions, 23 deletions
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 366daf1d044e..75af2d6e0e78 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -56,8 +56,14 @@
 #define DA7210_DAI_SRC_SEL		0x25
 #define DA7210_DAI_CFG1			0x26
 #define DA7210_DAI_CFG3			0x28
+#define DA7210_PLL_DIV1			0x29
+#define DA7210_PLL_DIV2			0x2A
 #define DA7210_PLL_DIV3			0x2B
 #define DA7210_PLL			0x2C
+#define DA7210_A_HID_UNLOCK		0x8A
+#define DA7210_A_TEST_UNLOCK		0x8B
+#define DA7210_A_PLL1			0x90
+#define DA7210_A_CP_MODE		0xA7
 
 /* STARTUP1 bit fields */
 #define DA7210_SC_MST_EN		(1 << 0)
@@ -75,15 +81,14 @@
 /* INMIX_R bit fields */
 #define DA7210_IN_R_EN			(1 << 7)
 
-/* ADC_HPF bit fields */
-#define DA7210_ADC_VOICE_EN		(1 << 7)
-
 /* ADC bit fields */
 #define DA7210_ADC_L_EN			(1 << 3)
 #define DA7210_ADC_R_EN			(1 << 7)
 
-/* DAC_HPF fields */
-#define DA7210_DAC_VOICE_EN		(1 << 7)
+/* DAC/ADC HPF fields */
+#define DA7210_VOICE_F0_MASK		(0x7 << 4)
+#define DA7210_VOICE_F0_25		(1 << 4)
+#define DA7210_VOICE_EN			(1 << 7)
 
 /* DAC_SEL bit fields */
 #define DA7210_DAC_L_SRC_DAI_L		(4 << 0)
@@ -124,7 +129,19 @@
 #define DA7210_PLL_BYP			(1 << 6)
 
 /* PLL bit fields */
-#define DA7210_PLL_FS_48000		(11 << 0)
+#define DA7210_PLL_FS_MASK		(0xF << 0)
+#define DA7210_PLL_FS_8000		(0x1 << 0)
+#define DA7210_PLL_FS_11025		(0x2 << 0)
+#define DA7210_PLL_FS_12000		(0x3 << 0)
+#define DA7210_PLL_FS_16000		(0x5 << 0)
+#define DA7210_PLL_FS_22050		(0x6 << 0)
+#define DA7210_PLL_FS_24000		(0x7 << 0)
+#define DA7210_PLL_FS_32000		(0x9 << 0)
+#define DA7210_PLL_FS_44100		(0xA << 0)
+#define DA7210_PLL_FS_48000		(0xB << 0)
+#define DA7210_PLL_FS_88200		(0xE << 0)
+#define DA7210_PLL_FS_96000		(0xF << 0)
+#define DA7210_PLL_EN			(0x1 << 7)
 
 #define DA7210_VERSION "0.0.1"
 
@@ -165,7 +182,7 @@ static const u8 da7210_reg[] = {
 static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg)
 {
 	u8 *cache = codec->reg_cache;
-	BUG_ON(reg > ARRAY_SIZE(da7210_reg));
+	BUG_ON(reg >= ARRAY_SIZE(da7210_reg));
 	return cache[reg];
 }
 
@@ -242,7 +259,8 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 	struct snd_soc_device *socdev = rtd->socdev;
 	struct snd_soc_codec *codec = socdev->card->codec;
 	u32 dai_cfg1;
-	u32 reg, mask;
+	u32 hpf_reg, hpf_mask, hpf_value;
+	u32 fs, bypass;
 
 	/* set DAI source to Left and Right ADC */
 	da7210_write(codec, DA7210_DAI_SRC_SEL,
@@ -266,25 +284,84 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
 
 	da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
 
-	/* FIXME
-	 *
-	 * It support 48K only now
-	 */
+	hpf_reg = (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) ?
+		DA7210_DAC_HPF : DA7210_ADC_HPF;
+
 	switch (params_rate(params)) {
+	case 8000:
+		fs		= DA7210_PLL_FS_8000;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		bypass		= DA7210_PLL_BYP;
+		break;
+	case 11025:
+		fs		= DA7210_PLL_FS_11025;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		bypass		= 0;
+		break;
+	case 12000:
+		fs		= DA7210_PLL_FS_12000;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		bypass		= DA7210_PLL_BYP;
+		break;
+	case 16000:
+		fs		= DA7210_PLL_FS_16000;
+		hpf_mask	= DA7210_VOICE_F0_MASK	| DA7210_VOICE_EN;
+		hpf_value	= DA7210_VOICE_F0_25	| DA7210_VOICE_EN;
+		bypass		= DA7210_PLL_BYP;
+		break;
+	case 22050:
+		fs		= DA7210_PLL_FS_22050;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		bypass		= 0;
+		break;
+	case 32000:
+		fs		= DA7210_PLL_FS_32000;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		bypass		= DA7210_PLL_BYP;
+		break;
+	case 44100:
+		fs		= DA7210_PLL_FS_44100;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		bypass		= 0;
+		break;
 	case 48000:
-		if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
-			reg  = DA7210_DAC_HPF;
-			mask = DA7210_DAC_VOICE_EN;
-		} else {
-			reg  = DA7210_ADC_HPF;
-			mask = DA7210_ADC_VOICE_EN;
-		}
+		fs		= DA7210_PLL_FS_48000;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		bypass		= DA7210_PLL_BYP;
+		break;
+	case 88200:
+		fs		= DA7210_PLL_FS_88200;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		bypass		= 0;
+		break;
+	case 96000:
+		fs		= DA7210_PLL_FS_96000;
+		hpf_mask	= DA7210_VOICE_EN;
+		hpf_value	= 0;
+		bypass		= DA7210_PLL_BYP;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-	snd_soc_update_bits(codec, reg, mask, 0);
+	/* Disable active mode */
+	snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+
+	snd_soc_update_bits(codec, hpf_reg, hpf_mask, hpf_value);
+	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
+	snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
+
+	/* Enable active mode */
+	snd_soc_update_bits(codec, DA7210_STARTUP1,
+			    DA7210_SC_MST_EN, DA7210_SC_MST_EN);
 
 	return 0;
 }
@@ -362,6 +439,7 @@ struct snd_soc_dai da7210_dai = {
 		.formats = DA7210_FORMATS,
 	},
 	.ops = &da7210_dai_ops,
+	.symmetric_rates = 1,
 };
 EXPORT_SYMBOL_GPL(da7210_dai);
 
@@ -383,7 +461,7 @@ static int da7210_init(struct da7210_priv *da7210)
 	INIT_LIST_HEAD(&codec->dapm_widgets);
 	INIT_LIST_HEAD(&codec->dapm_paths);
 
-	codec->private_data	= da7210;
+	snd_soc_codec_set_drvdata(codec, da7210);
 	codec->name		= "DA7210";
 	codec->owner		= THIS_MODULE;
 	codec->read		= da7210_read;
@@ -416,9 +494,23 @@ static int da7210_init(struct da7210_priv *da7210)
 	/* FIXME
 	 *
 	 * This driver use fixed value here
+	 * And below settings expects MCLK = 12.288MHz
+	 *
+	 * When you select different MCLK, please check...
+	 *      DA7210_PLL_DIV1 val
+	 *      DA7210_PLL_DIV2 val
+	 *      DA7210_PLL_DIV3 val
+	 *      DA7210_PLL_DIV3 :: DA7210_MCLK_RANGExxx
 	 */
 
 	/*
+	 * make sure that DA7210 use bypass mode before start up
+	 */
+	da7210_write(codec, DA7210_STARTUP1, 0);
+	da7210_write(codec, DA7210_PLL_DIV3,
+		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+
+	/*
 	 * ADC settings
 	 */
 
@@ -454,9 +546,28 @@ static int da7210_init(struct da7210_priv *da7210)
 	/* Diable PLL and bypass it */
 	da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
 
-	/* Bypass PLL and set MCLK freq rang to 10-20MHz */
-	da7210_write(codec, DA7210_PLL_DIV3,
+	/*
+	 * If 48kHz sound came, it use bypass mode,
+	 * and when it is 44.1kHz, it use PLL.
+	 *
+	 * This time, this driver sets PLL always ON
+	 * and controls bypass/PLL mode by switching
+	 * DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
+	 *   see da7210_hw_params
+	 */
+	da7210_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
+	da7210_write(codec, DA7210_PLL_DIV2, 0x99);
+	da7210_write(codec, DA7210_PLL_DIV3, 0x0A |
 		     DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+	snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+
+	/* As suggested by Dialog */
+	da7210_write(codec, DA7210_A_HID_UNLOCK,	0x8B); /* unlock */
+	da7210_write(codec, DA7210_A_TEST_UNLOCK,	0xB4);
+	da7210_write(codec, DA7210_A_PLL1,		0x01);
+	da7210_write(codec, DA7210_A_CP_MODE,		0x7C);
+	da7210_write(codec, DA7210_A_HID_UNLOCK,	0x00); /* re-lock */
+	da7210_write(codec, DA7210_A_TEST_UNLOCK,	0x00);
 
 	/* Activate all enabled subsystem */
 	da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);