[alsa-devel] [PATCH 1/2] ALSA: ASoc: TLV320AIC3X: ad SPI and clock on GPIO2 or BCLK

Prchal Jiří jiri.prchal at aksignal.cz
Mon Apr 4 09:49:49 CEST 2011



Dne 2.4.2011 10:26, Mark Brown napsal(a):
> On Thu, Mar 24, 2011 at 11:20:45AM +0100, Prchal Ji?? wrote:
>> Hi,
>> this patch ads SPI communication for codecs TLV320AIC3X and clock input on GPIO2 or BCLK.
>> Tested on TLV320AIC3106 and AT91SAM9260.
>> TODO: Set the model in SPI probe the right way. I don't know how.
> 
> Register two SPI drivers with different names.
???

>> This codec communicates on SPI in 1st byte: 7 MSB is register address, 1 LSB is read/write, 2nd byte data. For this
>> reason there is new functions in soc-cache.c snd_soc_7_8_*.
> 
> This looks mostly good but there's some cleanups needed, mostly from
> extra stuff which snuck in there, and you need to rebase against current
> code.
What cleanup? I copy functions snd_soc_8_8_* and made change to 7_8.

> As covered in SubmittingPatches you should always CC maintainers on
> patches.
Who is maintainer? I didn't find anyone, so I CC to author.

>>  config SND_SOC_AD73311
>>  	tristate
>> -
>> +
> 
> Random whitespace change, should be removed.
Yes.

>>   * Author:      Vladimir Barinov, <vbarinov at embeddedalley.com>
>> + *              Jiri Prchal, <jiri.prchal at aksignal.cz
> 
> If you're going to do this you probably want a > in there.
OK

>>  {
>>  	struct snd_soc_codec *codec = codec_dai->codec;
>>  	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
>> +	u8 data;
>> +
>> +	/* set external clock on GPIO2 or BCLK */
>> +	data = snd_soc_read(codec, AIC3X_CLKGEN_CTRL_REG);
>> +	data &= 0x0f;
>> +	data |= ((clk_id << PLLCLK_IN_SHIFT) | (clk_id << CLKDIV_IN_SHIFT));
>> +	snd_soc_write(codec, AIC3X_CLKGEN_CTRL_REG, data);
> 
> This looks like an unrelated change which is specific to your board.
> You should add an interface for configuring this functionality .
No, it's for all, who uses other clock source. Interface is standard function:
	/* Set the codec system clock for DAC and ADC */
	ret = snd_soc_dai_set_sysclk(codec_dai,
				     CLKIN_BCLK, cdu_audio[i].codecclk,
				     SND_SOC_CLOCK_IN);

>>  	if (ret != 0) {
>> -		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
>> +		dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
> 
> Why are you decapitalising th estart of the sentance here?
Corrected.

>> +static struct spi_driver aic3x_spi_driver = {
>> +	.driver = {
>> +		.name	= "tlv320aic3x-codec",
>> +		.owner	= THIS_MODULE,
> 
> Remove the -codec from the driver name.
Why? In I2C part it must be there, so should it be same?

>> +/* special functions for codecs with 7 bit register address and LSB read/write (like TLV320AIC3X) */
>> +static unsigned int snd_soc_7_8_read(struct snd_soc_codec *codec,
>> +				     unsigned int reg)
>> +{
>> +	int ret;
>> +	unsigned int val;
> 
> This won't apply against the current kernel and should be a separate
> patch, it's a generic thing rather than part of the CODEC driver.
I split it to another PATCH.

> --
> To unsubscribe from this list: send the line "unsubscribe alsa-devel" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/codecs/Kconfig
linux-2.6.38-patch/sound/soc/codecs/Kconfig
--- linux-2.6.38-vanilla/sound/soc/codecs/Kconfig	2011-03-15 02:20:32.000000000 +0100
+++ linux-2.6.38-patch/sound/soc/codecs/Kconfig	2011-04-04 08:30:12.115356779 +0200
@@ -37,7 +37,7 @@ config SND_SOC_ALL_CODECS
 	select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
 	select SND_SOC_TLV320AIC23 if I2C
 	select SND_SOC_TLV320AIC26 if SPI_MASTER
-	select SND_SOC_TLV320AIC3X if I2C
+	select SND_SOC_TLV320AIC3X if SND_SOC_I2C_AND_SPI
 	select SND_SOC_TPA6130A2 if I2C
 	select SND_SOC_TLV320DAC33 if I2C
 	select SND_SOC_TWL4030 if TWL4030_CORE
diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/codecs/tlv320aic3x.c
linux-2.6.38-patch/sound/soc/codecs/tlv320aic3x.c
--- linux-2.6.38-vanilla/sound/soc/codecs/tlv320aic3x.c	2011-03-15 02:20:32.000000000 +0100
+++ linux-2.6.38-patch/sound/soc/codecs/tlv320aic3x.c	2011-04-04 08:31:33.521844547 +0200
@@ -2,7 +2,9 @@
  * ALSA SoC TLV320AIC3X codec driver
  *
  * Author:      Vladimir Barinov, <vbarinov at embeddedalley.com>
+ *              Jiri Prchal, <jiri.prchal at aksignal.cz>
  * Copyright:   (C) 2007 MontaVista Software, Inc., <source at mvista.com>
+ *              (C) 2011 AK signal Brno
  *
  * Based on sound/soc/codecs/wm8753.c by Liam Girdwood
  *
@@ -42,6 +44,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/spi/spi.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
@@ -864,9 +867,15 @@ static int aic3x_hw_params(struct snd_pc
 		snd_soc_write(codec, AIC3X_PLL_PROGA_REG, reg | PLL_ENABLE);
 	}

-	/* Route Left DAC to left channel input and
-	 * right DAC to right channel input */
-	data = (LDAC2LCH | RDAC2RCH);
+	/* If is stereo: Route Left DAC to left channel input and
+	 * right DAC to right channel input
+	 * else mono: route left input to both DAC
+	 */
+	if (params_channels(params) == 2)
+		data = (LDAC2LCH | RDAC2RCH);
+	else
+		data = (LDAC2LCH | RDAC2LCH);
+
 	data |= (fsref == 44100) ? FSREF_44100 : FSREF_48000;
 	if (params_rate(params) >= 64000)
 		data |= DUAL_RATE_MODE;
@@ -984,6 +993,13 @@ static int aic3x_set_dai_sysclk(struct s
 {
 	struct snd_soc_codec *codec = codec_dai->codec;
 	struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+	u8 data;
+
+	/* set external clock on GPIO2 or BCLK */
+	data = snd_soc_read(codec, AIC3X_CLKGEN_CTRL_REG);
+	data &= 0x0f;
+	data |= ((clk_id << PLLCLK_IN_SHIFT) | (clk_id << CLKDIV_IN_SHIFT));
+	snd_soc_write(codec, AIC3X_CLKGEN_CTRL_REG, data);

 	aic3x->sysclk = freq;
 	return 0;
@@ -1371,7 +1387,10 @@ static int aic3x_probe(struct snd_soc_co
 	aic3x->codec = codec;
 	codec->dapm.idle_bias_off = 1;

-	ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+	if (aic3x->control_type == SND_SOC_I2C)
+		ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
+	else
+		ret = snd_soc_codec_set_cache_io(codec, 7, 8, aic3x->control_type);
 	if (ret != 0) {
 		dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 		return ret;
@@ -1472,6 +1491,54 @@ static struct snd_soc_codec_driver soc_c
 	.resume = aic3x_resume,
 };

+#if defined(CONFIG_SPI_MASTER)
+static int aic3x_spi_probe(struct spi_device *spi)
+{
+	struct aic3x_pdata *pdata = spi->dev.platform_data;
+	struct aic3x_priv *aic3x;
+	int ret;
+
+	aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
+	if (aic3x == NULL) {
+		dev_err(&spi->dev, "failed to create private data\n");
+		return -ENOMEM;
+	}
+
+	aic3x->control_type = SND_SOC_SPI;
+	spi_set_drvdata(spi, aic3x);
+
+	if (pdata) {
+		aic3x->gpio_reset = pdata->gpio_reset;
+		aic3x->setup = pdata->setup;
+	} else {
+		aic3x->gpio_reset = -1;
+	}
+
+	aic3x->model = AIC3X_MODEL_3X;
+
+	ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_aic3x, &aic3x_dai, 1);
+	if (ret < 0)
+		kfree(aic3x);
+	return ret;
+}
+
+static int __devexit aic3x_spi_remove(struct spi_device *spi)
+{
+	snd_soc_unregister_codec(&spi->dev);
+	kfree(spi_get_drvdata(spi));
+	return 0;
+}
+
+static struct spi_driver aic3x_spi_driver = {
+	.driver = {
+		.name	= "tlv320aic3x-codec",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= aic3x_spi_probe,
+	.remove		= __devexit_p(aic3x_spi_remove),
+};
+#endif /* CONFIG_SPI_MASTER */
+
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 /*
  * AIC3X 2 wire address can be up to 4 devices with device addresses
@@ -1557,6 +1624,13 @@ static int __init aic3x_modinit(void)
 		       ret);
 	}
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	ret = spi_register_driver(&aic3x_spi_driver);
+	if (ret != 0) {
+		printk(KERN_ERR "Failed to register AIC3X SPI driver: %d\n",
+		       ret);
+	}
+#endif
 	return ret;
 }
 module_init(aic3x_modinit);
@@ -1566,6 +1640,9 @@ static void __exit aic3x_exit(void)
 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
 	i2c_del_driver(&aic3x_i2c_driver);
 #endif
+#if defined(CONFIG_SPI_MASTER)
+	spi_unregister_driver(&aic3x_spi_driver);
+#endif
 }
 module_exit(aic3x_exit);

diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/codecs/tlv320aic3x.h
linux-2.6.38-patch/sound/soc/codecs/tlv320aic3x.h
--- linux-2.6.38-vanilla/sound/soc/codecs/tlv320aic3x.h	2011-03-15 02:20:32.000000000 +0100
+++ linux-2.6.38-patch/sound/soc/codecs/tlv320aic3x.h	2011-03-25 12:15:06.620049184 +0100
@@ -163,6 +163,10 @@
 #define DUAL_RATE_MODE		((1 << 5) | (1 << 6))
 #define LDAC2LCH		(0x1 << 3)
 #define RDAC2RCH		(0x1 << 1)
+#define LDAC2RCH		(0x2 << 3)
+#define RDAC2LCH		(0x2 << 1)
+#define LDAC2MONOMIX		(0x3 << 3)
+#define RDAC2MONOMIX		(0x3 << 1)

 /* PLL registers bitfields */
 #define PLLP_SHIFT		0
@@ -178,6 +182,13 @@
 #define PLL_CLKIN_SHIFT		4
 #define MCLK_SOURCE		0x0
 #define PLL_CLKDIV_SHIFT	0
+#define PLLCLK_IN_SHIFT		4
+#define CLKDIV_IN_SHIFT		6
+/* clock in source */
+#define CLKIN_MCLK		0
+#define CLKIN_GPIO2		1
+#define CLKIN_BCLK		2
+

 /* Software reset register bits */
 #define SOFT_RESET		0x80
--
To unsubscribe from this list: send the line "unsubscribe alsa-devel" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html



More information about the Alsa-devel mailing list