All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Prchal Jiří" <jiri.prchal@aksignal.cz>
To: Ryan Mallon <ryan@bluewatersys.com>
Cc: alsa-devel@vger.kernel.org, alsa-devel@alsa-project.org,
	vbarinov@embeddedalley.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 2/2] ALSA: ASoc: putting together AT91SAM9260 and TLV320AIC3X
Date: Mon, 04 Apr 2011 10:57:01 +0200	[thread overview]
Message-ID: <4D9987DD.8040703@aksignal.cz> (raw)
In-Reply-To: <4D8BA47B.8050904@bluewatersys.com>

Hi,
this is separeted PATCH for glue AT91SAM9260 and TLV320AIC3X on CDU board.

Depend on: [PATCH 1/2] ALSA: ASoc: TLV320AIC3X: ad SPI and clock on GPIO2 or BCLK
	[PATCH] ALSA: ASoc: new functions snd_soc_7_8_*
	[PATCH] ARCH arm: adding new board: CDU
Kernel version: 2.6.38
Signed-off-by: Jiri Prchal <jiri.prchal@aksignal.cz>

Dne 24.3.2011 21:07, Ryan Mallon napsal(a):
> On 03/24/2011 11:43 PM, Prchal Jiří wrote:
>> Hi,
>> this patch is for example how to put together AT91SAM9260 and TLV320AIC3106 controlled via SPI.
>> It tooks me a lot of time to make it working, so I think it could be helpfull for other people.
>>
>> In original source "snd-soc-afeb9260.c" which I use as example is BIG ERROR:
>> In function "afeb9260_soc_init" is missing call of "atmel_ssc_set_audio(0);". It cause bug "PROBLEM: Asoc driver in
>> 2.6.37.3 for AT91SAM9260 / TLV320AIC3X is broken" which I post some time ago.
> 
> Hi Jiri,
> 
> This patch is actually doing two things: adding board support for a new
> at91sam9260 device and adding the audio glue for the new board. It
> should be split into two patches. Quick review below.
> 
> ~Ryan
> 
I separate it.

>>
>> Depend on: [PATCH 1/2] ALSA: ASoc: TLV320AIC3X: ad SPI and clock on GPIO2 or BCLK
>> Kernel version: 2.6.38
>> Signed-off-by: Jiri Prchal <jiri.prchal@aksignal.cz>
>> ---
>>
>> diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/atmel/Kconfig
>> /home/prchal/arm/fw-cdu/linux/linux-2.6.38/sound/soc/atmel/Kconfig
>> --- linux-2.6.38-vanilla/sound/soc/atmel/Kconfig	2011-03-15 02:20:32.000000000 +0100
>> +++ /home/prchal/arm/fw-cdu/linux/linux-2.6.38/sound/soc/atmel/Kconfig	2011-03-22 09:46:46.751566158 +0100
>> @@ -50,3 +50,11 @@ config SND_AT91_SOC_AFEB9260
>>  	select SND_SOC_TLV320AIC23
>>  	help
>>  	  Say Y here to support sound on AFEB9260 board.
>> +
>> +config SND_AT91_SOC_CDU
>> +	tristate "SoC Audio support for CDU board"
>> +	depends on ARCH_AT91 && MACH_CDU && SND_ATMEL_SOC
>> +	select SND_ATMEL_SOC_SSC
>> +	select SND_SOC_TLV320AIC3X
>> +	help
>> +	  Say Y here to support sound on CDU board.
>> diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/atmel/Makefile
>> /home/prchal/arm/fw-cdu/linux/linux-2.6.38/sound/soc/atmel/Makefile
>> --- linux-2.6.38-vanilla/sound/soc/atmel/Makefile	2011-03-15 02:20:32.000000000 +0100
>> +++ /home/prchal/arm/fw-cdu/linux/linux-2.6.38/sound/soc/atmel/Makefile	2011-03-16 09:26:17.000000000 +0100
>> @@ -14,3 +14,4 @@ snd-soc-playpaq-objs := playpaq_wm8510.o
>>  obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
>>  obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
>>  obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
>> +obj-$(CONFIG_SND_AT91_SOC_CDU) += snd-soc-cdu.o
>> diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/atmel/snd-soc-cdu.c
>> /home/prchal/arm/fw-cdu/linux/linux-2.6.38/sound/soc/atmel/snd-soc-cdu.c
>> --- linux-2.6.38-vanilla/sound/soc/atmel/snd-soc-cdu.c	1970-01-01 01:00:00.000000000 +0100
>> +++ /home/prchal/arm/fw-cdu/linux/linux-2.6.38/sound/soc/atmel/snd-soc-cdu.c	2011-03-24 09:27:55.404367652 +0100
>> @@ -0,0 +1,264 @@
>> +/*
>> + * snd-soc-cdu  --  SoC audio for AT91SAM9260-based
>> + * 			AKsignal CDU board.
>> + *
>> + *  Copyright (C) 2005 SAN People
>> + *  Copyright (C) 2008 Atmel
>> + *  Copyright (C) 2011 AK signal Brno
>> + *
>> + * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
>> + *          Jiri Prchal <jiri.prchal@aksignal.cz>
>> + *
>> + * Based on ati_b1_wm8731.c by:
>> + * Frank Mandarino <fmandarino@endrelia.com>
>> + * Copyright 2006 Endrelia Technologies Inc.
>> + * Based on corgi.c by:
>> + * Copyright 2005 Wolfson Microelectronics PLC.
>> + * Copyright 2005 Openedhand Ltd.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/moduleparam.h>
>> +#include <linux/kernel.h>
>> +#include <linux/clk.h>
>> +#include <linux/timer.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/i2c.h>
>> +
>> +#include <linux/atmel-ssc.h>
>> +#include <sound/core.h>
>> +#include <sound/pcm.h>
>> +#include <sound/pcm_params.h>
>> +#include <sound/soc.h>
>> +
>> +#include <asm/mach-types.h>
>> +#include <mach/hardware.h>
>> +#include <mach/gpio.h>
> 
> Note sure you need all of these includes. linux/interrupt.h,
> linux/moduleparam.h, linux/timer.h and mach/gpio.h at least appear to be
> uneccessary.
Cleaned up.

> 
>> +
>> +#include "../codecs/tlv320aic3x.h"
>> +#include "atmel-pcm.h"
>> +#include "atmel_ssc_dai.h"
>> +
>> +struct {
>> +	unsigned int channels;
>> +	snd_pcm_format_t format;
>> +	unsigned int rate;
>> +	unsigned int codecclk;
>> +	unsigned int cmrdiv;
>> +	unsigned int period;
>> +} cdu_audio[] = {
>> +	/* 16 bit stereo modes */
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 8000, 2096000, 25, 130,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 16000, 2496000, 21, 77,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 32000, 2496000, 21, 38,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 48000, 2016000, 26, 20,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 96000, 4032000, 13, 20,},
>> +
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 11025, 2381400, 22, 107,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 22050, 2381400, 22, 53,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 44100, 2381400, 22, 26,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 88200, 4762800, 11, 26,},
>> +
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 11520, 2626560, 20, 113,},
>> +	{2, SNDRV_PCM_FORMAT_S16_LE, 23040, 2626560, 20, 56,},
> 
> Can these be calculated rather than using a table? The first two values
> probably don't need to be in the table since they are always the same.
Explained in new comment why it is table. I made the table smaller.

> 
>> +
>> +};
>> +
>> +static int cdu_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params)
>> +{
>> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
>> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
>> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
>> +	int ret;
>> +	int i, found = 0;
>> +	snd_pcm_format_t format = params_format(params);
>> +	unsigned int rate = params_rate(params);
>> +	unsigned int channels = params_channels(params);
>> +
>> +	/* set codec DAI configuration */
>> +	ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
> 
> Long lines should be broken to fit inside 80 characters.
OK.

> 
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/* set cpu DAI configuration */
>> +	ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	/* find the correct audio parameters */
>> +	for (i = 0; i < ARRAY_SIZE(cdu_audio); i++) {
>> +		if (rate == cdu_audio[i].rate &&
>> +		    format == cdu_audio[i].format &&
>> +		    channels == cdu_audio[i].channels) {
>> +			found = 1;
>> +			break;
>> +		}
>> +	}
>> +	if (!found)
>> +		return -EINVAL;
> 
> Should maybe do this before doing the dai_set_fmt's since we only
> support some modes. Also:
> 
> 	/* Only support 2 channel S16_LE */
> 	if (channels != 2 || format != SNDRV_PCM_FORMAT_S16_LE)
> 		return -EINVAL;
> 
> 	/* Check rate support */
> 	for (i = 0; i < ARRAY_SIZE(cdc_audio); i++)
> 		if (rate == cdc_audio[i].rate) {
> 			found = 1;
> 			break;
> 		}
> 	if (!found)
> 		return -EINVAL;
> 
OK.

>> +
>> +	/* 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) {
>> +		printk(KERN_ERR "can't set codec system clock\n");
> 
> You should, I think, be able to do:
> 
> 	struct device *dev = rtd->card->dev;
> 
> 	dev_err(dev, "can't set codec system clock\n");
> 
> Same goes for other printks.
> 
OK.

>> +		return ret;
>> +	}
>> +
>> +	/* Set the cpu clock dividers to BCLK */
>> +	ret = snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_CMR_DIV, cdu_audio[i].cmrdiv);
>> +	ret |= snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_TCMR_PERIOD, cdu_audio[i].period);
>> +	ret |= snd_soc_dai_set_clkdiv(cpu_dai, ATMEL_SSC_RCMR_PERIOD, cdu_audio[i].period);
>> +	if (ret < 0) {
>> +		printk(KERN_ERR "can't set cpu system clock\n");
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static struct snd_soc_ops cdu_ops = {
>> +	.hw_params = cdu_hw_params,
>> +};
>> +
>> +static const struct snd_soc_dapm_widget cdu_dapm_widgets[] = {
>> +	SND_SOC_DAPM_HP("Headphone Jack", NULL),
>> +	SND_SOC_DAPM_LINE("Line Out", NULL),
>> +	SND_SOC_DAPM_MIC("Mic Jack", NULL),
>> +	SND_SOC_DAPM_LINE("Line In", NULL),
>> +};
>> +
>> +static const struct snd_soc_dapm_route intercon[] = {
>> +	/* Headphone connected to HPLOUT, HPROUT */
>> +	{"Headphone Jack", NULL, "HPLOUT"},
>> +	{"Headphone Jack", NULL, "HPROUT"},
>> +
>> +	/* Line Out connected to LLOUT, RLOUT */
>> +	{"Line Out", NULL, "LLOUT"},
>> +	{"Line Out", NULL, "RLOUT"},
>> +
>> +	/* Mic connected to (MIC3L | MIC3R) */
>> +	{"MIC3L", NULL, "Mic Bias 2V"},
>> +	{"MIC3R", NULL, "Mic Bias 2V"},
>> +	{"Mic Bias 2V", NULL, "Mic Jack"},
>> +
>> +	/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
>> +	{"LINE1L", NULL, "Line In"},
>> +	{"LINE2L", NULL, "Line In"},
>> +	{"LINE1R", NULL, "Line In"},
>> +	{"LINE2R", NULL, "Line In"},
>> +};
>> +
>> +/*
>> + * Logic for a aic3x as connected on a cdu board.
>> + */
>> +static int cdu_aic3x_init(struct snd_soc_pcm_runtime *rtd)
>> +{
>> +	struct snd_soc_codec *codec = rtd->codec;
>> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
>> +	struct snd_soc_dapm_context *dapm = &codec->dapm;
>> +	int ret;
>> +
>> +	printk(KERN_DEBUG "cdu_aic3x: cdu_aic3x_init called\n");
> 
> Is this line really needed?
> 
NO, removed.

>> +
>> +	/* Add specific widgets */
>> +	snd_soc_dapm_new_controls(dapm, cdu_dapm_widgets,
>> +				  ARRAY_SIZE(cdu_dapm_widgets));
>> +	/* Set up specific audio path interconnects */
>> +	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
>> +
>> +	/* always connected */
>> +	snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
>> +	snd_soc_dapm_enable_pin(dapm, "Line Out");
>> +	snd_soc_dapm_enable_pin(dapm, "Mic Jack");
>> +	snd_soc_dapm_enable_pin(dapm, "Line In");
>> +
>> +	snd_soc_dapm_sync(dapm);
> 
> IIRC, you no longer need to explicitly call snd_soc_dapm_enable_pin and
> snd_soc_dapm_sync. Somebody else can probably shed more light on this.
> 
Removed.

>> +
>> +	return 0;
>> +}
>> +
>> +static struct snd_soc_dai_link cdu_dai = {
>> +	.name		= "TLV320AIC3106",
>> +	.stream_name	= "PCM",
>> +	.cpu_dai_name	= "atmel-ssc-dai.0",
>> +	.codec_dai_name	= "tlv320aic3x-hifi",
>> +	.init = cdu_aic3x_init,
> 
> Tab-delimiting got messed here.
> 
OK.

>> +	.platform_name	= "atmel-pcm-audio",
>> +#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
>> +	.codec_name	= "tlv320aic3x-codec.0-001b",
>> +#endif
>> +#if defined(CONFIG_SPI_MASTER)
>> +	.codec_name	= "spi1.3",
>> +#endif
> 
> If both CONFIG_I2C and CONFIG_SPI_MASTER are set then you will have a
> broken build. Which one does the CDU board use?
> 
Since CDU use only SPI the I2C option removed.

>> +	.ops		= &cdu_ops,
>> +};
>> +
>> +static struct snd_soc_card snd_soc_cdu = {
>> +	.name		= "TLV320AIC3106",
>> +	.dai_link	= &cdu_dai,
>> +	.num_links	= 1,
>> +};
>> +
>> +static struct platform_device *cdu_snd_device;
>> +
>> +static int __init cdu_init(void)
>> +{
>> +	struct clk *pllb;
> 
> Remove this line, pllb is never used in this function.
> 
OK.

>> +	int ret;
>> +
>> +	ret = atmel_ssc_set_audio(0);
>> +	if (ret != 0) {
> 
> Nitpick. Just if (ret) is fine.
> 
OK.

>> +		pr_err("Failed to set SSC 0 for audio: %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	cdu_snd_device = platform_device_alloc("soc-audio", -1);
>> +	if (!cdu_snd_device) {
>> +		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
>> +		ret = -ENOMEM;
>> +	}
>> +
>> +	platform_set_drvdata(cdu_snd_device, &snd_soc_cdu);
>> +
>> +	ret = platform_device_add(cdu_snd_device);
>> +	if (ret) {
>> +		printk(KERN_ERR "ASoC: Platform device allocation failed\n");
> 
> Use pr_err to be consistent.
> 
OK.

>> +		goto err_device_add;
>> +	}
>> +
>> +	return ret;
>> +
>> +err_device_add:
>> +	platform_device_put(cdu_snd_device);
>> +err:
>> +	return ret;
>> +}
>> +
>> +static void __exit cdu_exit(void)
>> +{
>> +	platform_device_unregister(cdu_snd_device);
>> +	cdu_snd_device = NULL;
> 
> I don't think you need to set cdu_snd_device to NULL here.
> 
OK.

>> +}
>> +
>> +module_init(cdu_init);
>> +module_exit(cdu_exit);
>> +
>> +/* Module information */
>> +MODULE_AUTHOR("Jiri Prchal <jiri.prchal@aksignal.cz>");
>> +MODULE_DESCRIPTION("ALSA SoC CDU_AIC3X");
>> +MODULE_LICENSE("GPL");
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> Please read the FAQ at  http://www.tux.org/lkml/
> 
> 

diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/atmel/Kconfig
linux-2.6.38-patch/sound/soc/atmel/Kconfig
--- linux-2.6.38-vanilla/sound/soc/atmel/Kconfig	2011-03-15 02:20:32.000000000 +0100
+++ linux-2.6.38-patch/sound/soc/atmel/Kconfig	2011-03-22 09:46:46.751566158 +0100
@@ -50,3 +50,11 @@ config SND_AT91_SOC_AFEB9260
 	select SND_SOC_TLV320AIC23
 	help
 	  Say Y here to support sound on AFEB9260 board.
+
+config SND_AT91_SOC_CDU
+	tristate "SoC Audio support for CDU board"
+	depends on ARCH_AT91 && MACH_CDU && SND_ATMEL_SOC
+	select SND_ATMEL_SOC_SSC
+	select SND_SOC_TLV320AIC3X
+	help
+	  Say Y here to support sound on CDU board.
diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/atmel/Makefile
linux-2.6.38-patch/sound/soc/atmel/Makefile
--- linux-2.6.38-vanilla/sound/soc/atmel/Makefile	2011-03-15 02:20:32.000000000 +0100
+++ linux-2.6.38-patch/sound/soc/atmel/Makefile	2011-03-16 09:26:17.000000000 +0100
@@ -14,3 +14,4 @@ snd-soc-playpaq-objs := playpaq_wm8510.o
 obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
 obj-$(CONFIG_SND_AT32_SOC_PLAYPAQ) += snd-soc-playpaq.o
 obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
+obj-$(CONFIG_SND_AT91_SOC_CDU) += snd-soc-cdu.o
diff -uprN -X linux-2.6.38-vanilla/Documentation/dontdiff linux-2.6.38-vanilla/sound/soc/atmel/snd-soc-cdu.c
linux-2.6.38-patch/sound/soc/atmel/snd-soc-cdu.c
--- linux-2.6.38-vanilla/sound/soc/atmel/snd-soc-cdu.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.38-patch/sound/soc/atmel/snd-soc-cdu.c	2011-03-25 13:42:07.545051043 +0100
@@ -0,0 +1,259 @@
+/*
+ * snd-soc-cdu  --  SoC audio for AT91SAM9260-based
+ * 			AKsignal CDU board.
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2008 Atmel
+ *  Copyright (C) 2011 AK signal Brno
+ *
+ * Authors: Sedji Gaouaou <sedji.gaouaou@atmel.com>
+ *          Jiri Prchal <jiri.prchal@aksignal.cz>
+ *
+ * Based on ati_b1_wm8731.c by:
+ * Frank Mandarino <fmandarino@endrelia.com>
+ * Copyright 2006 Endrelia Technologies Inc.
+ * Based on corgi.c by:
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <linux/atmel-ssc.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "../codecs/tlv320aic3x.h"
+#include "atmel-pcm.h"
+#include "atmel_ssc_dai.h"
+
+/*
+ * Table of supported rates
+ * with their clock divider (cmrdiv) and number clock in frame (period + 1 * 2),
+ * codecclk sould be integer multiple of sample rate even if it is not exact true
+ * to avoid data on SSC underrun / overrun -
+ * CPU can not generate clock as fine as CODEC.
+ */
+struct {
+	unsigned int rate;
+	unsigned int codecclk;
+	unsigned int cmrdiv;
+	unsigned int period;
+} cdu_audio[] = {
+	{8000, 2096000, 25, 130,},
+	{16000, 2496000, 21, 77,},
+	{32000, 2496000, 21, 38,},
+	{48000, 2016000, 26, 20,},
+	{96000, 4032000, 13, 20,},
+
+	{11025, 2381400, 22, 107,},
+	{22050, 2381400, 22, 53,},
+	{44100, 2381400, 22, 26,},
+	{88200, 4762800, 11, 26,},
+
+	/* special rates for serial line transfer */
+	{11520, 2626560, 20, 113,},
+	{23040, 2626560, 20, 56,},
+	{46080, 2764800, 19, 29,},
+};
+
+static int cdu_hw_params(struct snd_pcm_substream *substream,
+			 struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct device *dev = rtd->card->dev;
+	int ret;
+	int i, found = 0;
+
+	/* set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai,
+				  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				  SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai,
+				  SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+				  SND_SOC_DAIFMT_CBS_CFS);
+	if (ret < 0)
+		return ret;
+
+	/* Only support 1 or 2 channel S16_LE */
+	if ((params_channels(params) != 1 && params_channels(params) != 2) ||
+	   params_format(params) != SNDRV_PCM_FORMAT_S16_LE)
+		return -EINVAL;
+
+	/* Check rate support */
+	for (i = 0; i < ARRAY_SIZE(cdu_audio); i++)
+		if (params_rate(params) == cdu_audio[i].rate) {
+			found = 1;
+			break;
+		}
+	if (!found)
+		return -EINVAL;
+
+	/* 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(dev, "can't set codec system clock\n");
+		return ret;
+	}
+
+	/* Set the cpu clock dividers to BCLK */
+	ret = snd_soc_dai_set_clkdiv(cpu_dai,
+				     ATMEL_SSC_CMR_DIV, cdu_audio[i].cmrdiv);
+	ret |= snd_soc_dai_set_clkdiv(cpu_dai,
+				      ATMEL_SSC_TCMR_PERIOD,
+				      cdu_audio[i].period);
+	ret |= snd_soc_dai_set_clkdiv(cpu_dai,
+				      ATMEL_SSC_RCMR_PERIOD,
+				      cdu_audio[i].period);
+	if (ret < 0) {
+		dev_err(dev, "can't set cpu system clock\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops cdu_ops = {
+	.hw_params = cdu_hw_params,
+};
+
+static const struct snd_soc_dapm_widget cdu_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line Out", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+	/* Headphone connected to HPLOUT, HPROUT */
+	{"Headphone Jack", NULL, "HPLOUT"},
+	{"Headphone Jack", NULL, "HPROUT"},
+
+	/* Line Out connected to LLOUT, RLOUT */
+	{"Line Out", NULL, "LLOUT"},
+	{"Line Out", NULL, "RLOUT"},
+
+	/* Mic connected to (MIC3L | MIC3R) */
+	{"MIC3L", NULL, "Mic Bias 2V"},
+	{"MIC3R", NULL, "Mic Bias 2V"},
+	{"Mic Bias 2V", NULL, "Mic Jack"},
+
+	/* Line In connected to (LINE1L | LINE2L), (LINE1R | LINE2R) */
+	{"LINE1L", NULL, "Line In"},
+	{"LINE2L", NULL, "Line In"},
+	{"LINE1R", NULL, "Line In"},
+	{"LINE2R", NULL, "Line In"},
+};
+
+/*
+ * Logic for a aic3x as connected on a cdu board.
+ */
+static int cdu_aic3x_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dapm_context *dapm = &codec->dapm;
+	int ret;
+
+	/* Add specific widgets */
+	snd_soc_dapm_new_controls(dapm, cdu_dapm_widgets,
+				  ARRAY_SIZE(cdu_dapm_widgets));
+	/* Set up specific audio path interconnects */
+	snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
+
+	return 0;
+}
+
+static struct snd_soc_dai_link cdu_dai = {
+	.name		= "TLV320AIC3106",
+	.stream_name	= "PCM",
+	.cpu_dai_name	= "atmel-ssc-dai.0",
+	.codec_dai_name	= "tlv320aic3x-hifi",
+	.init		= cdu_aic3x_init,
+	.platform_name	= "atmel-pcm-audio",
+	.codec_name	= "spi1.3",
+	.ops		= &cdu_ops,
+};
+
+static struct snd_soc_card snd_soc_cdu = {
+	.name		= "TLV320AIC3106",
+	.dai_link	= &cdu_dai,
+	.num_links	= 1,
+};
+
+static struct platform_device *cdu_snd_device;
+
+static int __init cdu_init(void)
+{
+	int ret;
+
+	ret = atmel_ssc_set_audio(0);
+	if (ret) {
+		pr_err("Failed to set SSC 0 for audio: %d\n", ret);
+		return ret;
+	}
+
+	cdu_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!cdu_snd_device) {
+		pr_err("ASoC: Platform device allocation failed: %d\n", ret);
+		ret = -ENOMEM;
+	}
+
+	platform_set_drvdata(cdu_snd_device, &snd_soc_cdu);
+
+	ret = platform_device_add(cdu_snd_device);
+	if (ret) {
+		pr_err("ASoC: Platform device adding failed: %d\n", ret);
+		goto err_device_add;
+	}
+
+	return ret;
+
+err_device_add:
+	platform_device_put(cdu_snd_device);
+err:
+	return ret;
+}
+
+static void __exit cdu_exit(void)
+{
+	platform_device_unregister(cdu_snd_device);
+}
+
+module_init(cdu_init);
+module_exit(cdu_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jiri Prchal <jiri.prchal@aksignal.cz>");
+MODULE_DESCRIPTION("ALSA SoC CDU_AIC3X");
+MODULE_LICENSE("GPL");

  reply	other threads:[~2011-04-04  8:57 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-03-24  6:54 [PATCH 0/2] mmc: zboot helpers Simon Horman
2011-03-24  6:54 ` Simon Horman
2011-03-24  6:54 ` [PATCH 1/2] mmc, ARM: Rename SuperH Mobile ARM " Simon Horman
2011-03-24  6:54   ` Simon Horman
2011-03-24  9:10   ` [PATCH] mmc, AT91: fix init fequency problem Prchal Jiří
2011-03-24  9:10     ` Prchal Jiří
2011-03-24 10:20   ` [PATCH 1/2] ALSA: ASoc: TLV320AIC3X: ad SPI and clock on GPIO2 or BCLK Prchal Jiří
2011-04-02  8:26     ` Mark Brown
2011-04-02  8:26       ` [alsa-devel] " Mark Brown
2011-04-04  7:49       ` Prchal Jiří
2011-04-04  8:03         ` Mark Brown
2011-04-04  8:01       ` [PATCH] ALSA: ASoc: new functions snd_soc_7_8_* Prchal Jiří
2011-04-04  8:05         ` Mark Brown
2011-04-04  8:05           ` Mark Brown
2011-03-24 10:43   ` [PATCH 2/2] ALSA: ASoc: putting together AT91SAM9260 and TLV320AIC3X Prchal Jiří
2011-03-24 20:07     ` Ryan Mallon
2011-03-24 20:07       ` Ryan Mallon
2011-04-04  8:57       ` Prchal Jiří [this message]
2011-04-04 20:07         ` Ryan Mallon
2011-04-04 20:07           ` Ryan Mallon
2011-04-04  9:10       ` [PATCH] ARCH arm: adding new board: CDU Prchal Jiří
2011-04-04  9:10         ` Prchal Jiří
2011-04-04  9:16         ` Russell King - ARM Linux
2011-04-04  9:16           ` Russell King - ARM Linux
2011-04-04  9:24           ` Russell King - ARM Linux
2011-04-04  9:24             ` Russell King - ARM Linux
2011-04-04 20:25         ` Ryan Mallon
2011-04-04 20:25           ` Ryan Mallon
2011-05-31 13:05       ` PROBLEM: ARM: PCM plugin Ima-ADPCM doesn't work properly Prchal Jiří
2011-03-24  6:54 ` [PATCH 2/2] mmc: Add MMC_PROGRESS_* Simon Horman
2011-03-24  6:54   ` Simon Horman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4D9987DD.8040703@aksignal.cz \
    --to=jiri.prchal@aksignal.cz \
    --cc=alsa-devel@alsa-project.org \
    --cc=alsa-devel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ryan@bluewatersys.com \
    --cc=vbarinov@embeddedalley.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.