Browse Source

Merge remote-tracking branches 'asoc/topic/ak4613', 'asoc/topic/ak4642', 'asoc/topic/atmel', 'asoc/topic/cs35l34' and 'asoc/topic/cs35l35' into asoc-next

Mark Brown 8 years ago

+ 3 - 0
Documentation/devicetree/bindings/sound/cs35l35.txt

@@ -16,6 +16,9 @@ Required properties:
     (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
     for further information relating to interrupt properties)
 
+ - cirrus,boost-ind-nanohenry: Inductor value for boost converter. The value is
+    in nH and they can be values of 1000nH, 1200nH, 1500nH, and 2200nH.
+
 Optional properties:
   - reset-gpios : gpio used to reset the amplifier
 

+ 2 - 0
include/sound/cs35l35.h

@@ -99,6 +99,8 @@ struct cs35l35_platform_data {
 	bool shared_bst;
 	/* Specifies this amp is using an external boost supply */
 	bool ext_bst;
+	/* Inductor Value */
+	int boost_ind;
 	/* ClassH Algorithm */
 	struct classh_cfg classh_algo;
 	/* Monitor Config */

+ 2 - 4
sound/soc/atmel/atmel-pcm.h

@@ -83,8 +83,7 @@ struct atmel_pcm_dma_params {
 #define ssc_readx(base, reg)            (__raw_readl((base) + (reg)))
 #define ssc_writex(base, reg, value)    __raw_writel((value), (base) + (reg))
 
-#if defined(CONFIG_SND_ATMEL_SOC_PDC) || \
-	defined(CONFIG_SND_ATMEL_SOC_PDC_MODULE)
+#if IS_ENABLED(CONFIG_SND_ATMEL_SOC_PDC)
 int atmel_pcm_pdc_platform_register(struct device *dev);
 void atmel_pcm_pdc_platform_unregister(struct device *dev);
 #else
@@ -97,8 +96,7 @@ static inline void atmel_pcm_pdc_platform_unregister(struct device *dev)
 }
 #endif
 
-#if defined(CONFIG_SND_ATMEL_SOC_DMA) || \
-	defined(CONFIG_SND_ATMEL_SOC_DMA_MODULE)
+#if IS_ENABLED(CONFIG_SND_ATMEL_SOC_DMA)
 int atmel_pcm_dma_platform_register(struct device *dev);
 void atmel_pcm_dma_platform_unregister(struct device *dev);
 #else

+ 78 - 15
sound/soc/codecs/ak4613.c

@@ -94,6 +94,8 @@ struct ak4613_interface {
 struct ak4613_priv {
 	struct mutex lock;
 	const struct ak4613_interface *iface;
+	struct snd_pcm_hw_constraint_list constraint;
+	unsigned int sysclk;
 
 	unsigned int fmt;
 	u8 oc;
@@ -139,9 +141,7 @@ static const struct reg_default ak4613_reg[] = {
 #define AUDIO_IFACE(b, fmt) { b, SND_SOC_DAIFMT_##fmt }
 static const struct ak4613_interface ak4613_iface[] = {
 	/* capture */				/* playback */
-	[0] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(16, RIGHT_J) },
-	[1] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(20, RIGHT_J) },
-	[2] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(24, RIGHT_J) },
+	/* [0] - [2] are not supported */
 	[3] = {	AUDIO_IFACE(24, LEFT_J),	AUDIO_IFACE(24, LEFT_J) },
 	[4] = {	AUDIO_IFACE(24, I2S),		AUDIO_IFACE(24, I2S) },
 };
@@ -254,6 +254,74 @@ static void ak4613_dai_shutdown(struct snd_pcm_substream *substream,
 	mutex_unlock(&priv->lock);
 }
 
+static void ak4613_hw_constraints(struct ak4613_priv *priv,
+				  struct snd_pcm_runtime *runtime)
+{
+	static const unsigned int ak4613_rates[] = {
+		 32000,
+		 44100,
+		 48000,
+		 64000,
+		 88200,
+		 96000,
+		176400,
+		192000,
+	};
+	struct snd_pcm_hw_constraint_list *constraint = &priv->constraint;
+	unsigned int fs;
+	int i;
+
+	constraint->list	= ak4613_rates;
+	constraint->mask	= 0;
+	constraint->count	= 0;
+
+	/*
+	 * Slave Mode
+	 *	Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs
+	 *	Double: [64kHz, 96kHz] : 256fs
+	 *	Quad  : [128kHz,192kHz]: 128fs
+	 *
+	 * Master mode
+	 *	Normal: [32kHz, 48kHz] : 256fs or 512fs
+	 *	Double: [64kHz, 96kHz] : 256fs
+	 *	Quad  : [128kHz,192kHz]: 128fs
+	*/
+	for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) {
+		/* minimum fs on each range */
+		fs = (ak4613_rates[i] <= 96000) ? 256 : 128;
+
+		if (priv->sysclk >= ak4613_rates[i] * fs)
+			constraint->count = i + 1;
+	}
+
+	snd_pcm_hw_constraint_list(runtime, 0,
+				SNDRV_PCM_HW_PARAM_RATE, constraint);
+}
+
+static int ak4613_dai_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_codec *codec = dai->codec;
+	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->cnt++;
+
+	ak4613_hw_constraints(priv, substream->runtime);
+
+	return 0;
+}
+
+static int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai,
+				 int clk_id, unsigned int freq, int dir)
+{
+	struct snd_soc_codec *codec = codec_dai->codec;
+	struct ak4613_priv *priv = snd_soc_codec_get_drvdata(codec);
+
+	priv->sysclk = freq;
+
+	return 0;
+}
+
 static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 {
 	struct snd_soc_codec *codec = dai->codec;
@@ -262,11 +330,9 @@ static int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 	fmt &= SND_SOC_DAIFMT_FORMAT_MASK;
 
 	switch (fmt) {
-	case SND_SOC_DAIFMT_RIGHT_J:
 	case SND_SOC_DAIFMT_LEFT_J:
 	case SND_SOC_DAIFMT_I2S:
 		priv->fmt = fmt;
-
 		break;
 	default:
 		return -EINVAL;
@@ -286,13 +352,8 @@ static bool ak4613_dai_fmt_matching(const struct ak4613_interface *iface,
 	if (fmts->fmt != fmt)
 		return false;
 
-	if (fmt == SND_SOC_DAIFMT_RIGHT_J) {
-		if (fmts->width != width)
-			return false;
-	} else {
-		if (fmts->width < width)
-			return false;
-	}
+	if (fmts->width != width)
+		return false;
 
 	return true;
 }
@@ -319,6 +380,7 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
 	case 48000:
 		ctrl2 = DFS_NORMAL_SPEED;
 		break;
+	case 64000:
 	case 88200:
 	case 96000:
 		ctrl2 = DFS_DOUBLE_SPEED;
@@ -358,7 +420,6 @@ static int ak4613_dai_hw_params(struct snd_pcm_substream *substream,
 	if ((priv->iface == NULL) ||
 	    (priv->iface == iface)) {
 		priv->iface = iface;
-		priv->cnt++;
 		ret = 0;
 	}
 	mutex_unlock(&priv->lock);
@@ -407,7 +468,9 @@ static int ak4613_set_bias_level(struct snd_soc_codec *codec,
 }
 
 static const struct snd_soc_dai_ops ak4613_dai_ops = {
+	.startup	= ak4613_dai_startup,
 	.shutdown	= ak4613_dai_shutdown,
+	.set_sysclk	= ak4613_dai_set_sysclk,
 	.set_fmt	= ak4613_dai_set_fmt,
 	.hw_params	= ak4613_dai_hw_params,
 };
@@ -420,8 +483,7 @@ static const struct snd_soc_dai_ops ak4613_dai_ops = {
 				 SNDRV_PCM_RATE_96000  |\
 				 SNDRV_PCM_RATE_176400 |\
 				 SNDRV_PCM_RATE_192000)
-#define AK4613_PCM_FMTBIT	(SNDRV_PCM_FMTBIT_S16_LE |\
-				 SNDRV_PCM_FMTBIT_S24_LE)
+#define AK4613_PCM_FMTBIT	(SNDRV_PCM_FMTBIT_S24_LE)
 
 static struct snd_soc_dai_driver ak4613_dai = {
 	.name = "ak4613-hifi",
@@ -527,6 +589,7 @@ static int ak4613_i2c_probe(struct i2c_client *i2c,
 
 	priv->iface		= NULL;
 	priv->cnt		= 0;
+	priv->sysclk		= 0;
 
 	mutex_init(&priv->lock);
 

+ 2 - 2
sound/soc/codecs/ak4642.c

@@ -433,7 +433,7 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
 static int ak4642_set_mcko(struct snd_soc_codec *codec,
 			   u32 frequency)
 {
-	u32 fs_list[] = {
+	static const u32 fs_list[] = {
 		[0] = 8000,
 		[1] = 12000,
 		[2] = 16000,
@@ -447,7 +447,7 @@ static int ak4642_set_mcko(struct snd_soc_codec *codec,
 		[14] = 29400,
 		[15] = 44100,
 	};
-	u32 ps_list[] = {
+	static const u32 ps_list[] = {
 		[0] = 256,
 		[1] = 128,
 		[2] = 64,

+ 2 - 2
sound/soc/codecs/cs35l34.c

@@ -567,12 +567,12 @@ static int cs35l34_pcm_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static unsigned int cs35l34_src_rates[] = {
+static const unsigned int cs35l34_src_rates[] = {
 	8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000
 };
 
 
-static struct snd_pcm_hw_constraint_list cs35l34_constraints = {
+static const struct snd_pcm_hw_constraint_list cs35l34_constraints = {
 	.count  = ARRAY_SIZE(cs35l34_src_rates),
 	.list   = cs35l34_src_rates,
 };

+ 83 - 1
sound/soc/codecs/cs35l35.c

@@ -764,6 +764,76 @@ static int cs35l35_codec_set_sysclk(struct snd_soc_codec *codec,
 	return ret;
 }
 
+static int cs35l35_boost_inductor(struct cs35l35_private *cs35l35,
+				  int inductor)
+{
+	struct regmap *regmap = cs35l35->regmap;
+	unsigned int bst_ipk = 0;
+
+	/*
+	 * Digital Boost Converter Configuration for feedback,
+	 * ramping, switching frequency, and estimation block seeding.
+	 */
+
+	regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+			   CS35L35_BST_CONV_SWFREQ_MASK, 0x00);
+
+	regmap_read(regmap, CS35L35_BST_PEAK_I, &bst_ipk);
+	bst_ipk &= CS35L35_BST_IPK_MASK;
+
+	switch (inductor) {
+	case 1000: /* 1 uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x24);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x24);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x00);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x4E);
+		break;
+	case 1200: /* 1.2 uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x01);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x47);
+		break;
+	case 1500: /* 1.5uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x20);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x20);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x02);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x3C);
+		break;
+	case 2200: /* 2.2uH */
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_1, 0x19);
+		regmap_write(regmap, CS35L35_BST_CONV_COEF_2, 0x25);
+		regmap_update_bits(regmap, CS35L35_BST_CONV_SW_FREQ,
+				   CS35L35_BST_CONV_LBST_MASK, 0x03);
+
+		if (bst_ipk < 0x04)
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x1B);
+		else
+			regmap_write(regmap, CS35L35_BST_CONV_SLOPE_COMP, 0x23);
+		break;
+	default:
+		dev_err(cs35l35->dev, "Invalid Inductor Value %d uH\n",
+			inductor);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int cs35l35_codec_probe(struct snd_soc_codec *codec)
 {
 	struct cs35l35_private *cs35l35 = snd_soc_codec_get_drvdata(codec);
@@ -783,6 +853,10 @@ static int cs35l35_codec_probe(struct snd_soc_codec *codec)
 				cs35l35->pdata.bst_ipk <<
 				CS35L35_BST_IPK_SHIFT);
 
+	ret = cs35l35_boost_inductor(cs35l35, cs35l35->pdata.boost_ind);
+	if (ret)
+		return ret;
+
 	if (cs35l35->pdata.gain_zc)
 		regmap_update_bits(cs35l35->regmap, CS35L35_PROTECT_CTL,
 				CS35L35_AMP_GAIN_ZC_MASK,
@@ -1203,7 +1277,15 @@ static int cs35l35_handle_of_data(struct i2c_client *i2c_client,
 			return -EINVAL;
 		}
 
-		pdata->bst_ipk = (val32 - 1680) / 110;
+		pdata->bst_ipk = ((val32 - 1680) / 110) | CS35L35_VALID_PDATA;
+	}
+
+	ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val32);
+	if (ret >= 0) {
+		pdata->boost_ind = val32;
+	} else {
+		dev_err(&i2c_client->dev, "Inductor not specified.\n");
+		return -EINVAL;
 	}
 
 	if (of_property_read_u32(np, "cirrus,sp-drv-strength", &val32) >= 0)

+ 6 - 0
sound/soc/codecs/cs35l35.h

@@ -200,6 +200,12 @@
 #define CS35L35_SP_I2S_DRV_MASK		0x03
 #define CS35L35_SP_I2S_DRV_SHIFT	0
 
+/* Boost Converter Config */
+#define CS35L35_BST_CONV_COEFF_MASK	0xFF
+#define CS35L35_BST_CONV_SLOPE_MASK	0xFF
+#define CS35L35_BST_CONV_LBST_MASK	0x03
+#define CS35L35_BST_CONV_SWFREQ_MASK	0xF0
+
 /* Class H Algorithm Control */
 #define CS35L35_CH_STEREO_MASK		0x40
 #define CS35L35_CH_STEREO_SHIFT		6