From patchwork Wed Jun 23 14:33:54 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Raffaele Recalcati X-Patchwork-Id: 107677 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter.kernel.org (8.14.4/8.14.3) with ESMTP id o5NK9Z9N001837 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 23 Jun 2010 20:10:11 GMT Received: from dlep33.itg.ti.com ([157.170.170.112]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id o5NK7tlx015131 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Wed, 23 Jun 2010 15:07:55 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id o5NK7tAx001444; Wed, 23 Jun 2010 15:07:55 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 902A880627; Wed, 23 Jun 2010 15:07:55 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp53.itg.ti.com (dflp53.itg.ti.com [128.247.5.6]) by linux.omap.com (Postfix) with ESMTP id CB40880626 for ; Wed, 23 Jun 2010 09:33:57 -0500 (CDT) Received: from red.ext.ti.com (localhost [127.0.0.1]) by dflp53.itg.ti.com (8.13.8/8.13.8) with ESMTP id o5NEXvbA005559 for ; Wed, 23 Jun 2010 09:33:57 -0500 (CDT) Received: from psmtp.com (na3sys009amx193.postini.com [74.125.149.174]) by red.ext.ti.com (8.13.7/8.13.7) with SMTP id o5NEXtV7013241 for ; Wed, 23 Jun 2010 09:33:55 -0500 Received: from source ([74.125.82.173]) by na3sys009amx193.postini.com ([74.125.148.10]) with SMTP; Wed, 23 Jun 2010 14:33:56 GMT Received: by wyb42 with SMTP id 42so1514193wyb.4 for ; Wed, 23 Jun 2010 07:33:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:from:to:cc:subject:date :message-id:x-mailer; bh=5jSJQFQm9Z9hpW+2ZsozVZ1pXczLaABL8m4UEN2BRhs=; b=O4xXLr90TJuCD5+II53bgT8k0qTmvZK4zWX2mDfqSpY8yUYDwiZu/1+Lv7mLCxzG0V MdBHj0gk9WWWs9Y+AVvHWLx/e1zJT+yDZiDpZd/BoVdvzqYhxR3qTMevO9pXSeI/zyHo V8oQYohvmhQgHJd9/JV3CvhrFSoKfAX8VirJ0= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=KweXRH5e+rGfmg3AnWSHm+d+tkhGmZS3aX+MKiP4Z9OoY1p6r/GVfc8vLLpFm0ZiAA 65rXh/qxP66jJZg2Ka6nnmogMalxM5AlqgCe9p2tKvMg8UE+a7GQE7Y3rGrj4OIPCIj7 ftP9olIU8G8nTjQGwGjsl7oFRszq0UTZ0AV3Y= Received: by 10.227.129.7 with SMTP id m7mr7634249wbs.137.1277303630219; Wed, 23 Jun 2010 07:33:50 -0700 (PDT) Received: from localhost.localdomain (host81-90-static.72-81-b.business.telecomitalia.it [81.72.90.81]) by mx.google.com with ESMTPS id n31sm61093963wba.15.2010.06.23.07.33.47 (version=TLSv1/SSLv3 cipher=RC4-MD5); Wed, 23 Jun 2010 07:33:49 -0700 (PDT) From: Raffaele Recalcati To: davinci-linux-open-source@linux.davincidsp.com Subject: [PATCH] ASoC: DaVinci: Added support for stereo I2S Date: Wed, 23 Jun 2010 16:33:54 +0200 Message-Id: <1277303635-5675-1-git-send-email-lamiaposta71@gmail.com> X-Mailer: git-send-email 1.7.0.4 X-pstn-levels: (S:27.87406/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:97.0282 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.5000) s cv gt3 gt2 gt1 r p m c X-pstn-addresses: from [db-null] X-Mailman-Approved-At: Wed, 23 Jun 2010 15:07:54 -0500 Cc: alsa-devel@alsa-project.org, Russell King , Takashi Iwai , Mark Brown , linux-kernel@vger.kernel.org, Raffaele Recalcati , Jaroslav Kysela , linux-arm-kernel@lists.infradead.org, Liam Girdwood X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Wed, 23 Jun 2010 20:10:12 +0000 (UTC) diff --git a/arch/arm/mach-davinci/include/mach/asp.h b/arch/arm/mach-davinci/include/mach/asp.h index 834725f..b1faeb9 100644 --- a/arch/arm/mach-davinci/include/mach/asp.h +++ b/arch/arm/mach-davinci/include/mach/asp.h @@ -63,6 +63,13 @@ struct snd_platform_data { unsigned sram_size_playback; unsigned sram_size_capture; + /* + * This define works when both clock and FS are output for the cpu + * and makes clock very fast (FS is not simmetrical, but sampling + * frequency is better approximated + */ + int i2s_fast_clock; + /* McASP specific fields */ int tdm_slots; u8 op_mode; diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index adadcd3..8811d25 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -68,16 +68,23 @@ #define DAVINCI_MCBSP_RCR_RDATDLY(v) ((v) << 16) #define DAVINCI_MCBSP_RCR_RFIG (1 << 18) #define DAVINCI_MCBSP_RCR_RWDLEN2(v) ((v) << 21) +#define DAVINCI_MCBSP_RCR_RFRLEN2(v) ((v) << 24) +#define DAVINCI_MCBSP_RCR_RPHASE (1 << 31) #define DAVINCI_MCBSP_XCR_XWDLEN1(v) ((v) << 5) #define DAVINCI_MCBSP_XCR_XFRLEN1(v) ((v) << 8) #define DAVINCI_MCBSP_XCR_XDATDLY(v) ((v) << 16) #define DAVINCI_MCBSP_XCR_XFIG (1 << 18) #define DAVINCI_MCBSP_XCR_XWDLEN2(v) ((v) << 21) +#define DAVINCI_MCBSP_XCR_XFRLEN2(v) ((v) << 24) +#define DAVINCI_MCBSP_XCR_XPHASE (1 << 31) + +#define CLKGDV(v) (v) /* Bits 0:7 */ #define DAVINCI_MCBSP_SRGR_FWID(v) ((v) << 8) #define DAVINCI_MCBSP_SRGR_FPER(v) ((v) << 16) #define DAVINCI_MCBSP_SRGR_FSGM (1 << 28) +#define DAVINCI_MCBSP_SRGR_CLKSM (1 << 29) #define DAVINCI_MCBSP_PCR_CLKRP (1 << 0) #define DAVINCI_MCBSP_PCR_CLKXP (1 << 1) @@ -144,8 +151,17 @@ struct davinci_mcbsp_dev { * won't end up being swapped because of the underrun. */ unsigned enable_channel_combine:1; + + int i2s_fast_clock; +}; + +struct davinci_mcbsp_data { + unsigned int fmt; + int clk_div; }; +static struct davinci_mcbsp_data mcbsp_data; + static inline void davinci_mcbsp_write_reg(struct davinci_mcbsp_dev *dev, int reg, u32 val) { @@ -255,24 +271,27 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int pcr; unsigned int srgr; srgr = DAVINCI_MCBSP_SRGR_FSGM | - DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | - DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); + DAVINCI_MCBSP_SRGR_FPER(DEFAULT_BITPERSAMPLE * 2 - 1) | + DAVINCI_MCBSP_SRGR_FWID(DEFAULT_BITPERSAMPLE - 1); + /* Attention srgr is updated by hw_params! */ + mcbsp_data.fmt = fmt; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBS_CFM: case SND_SOC_DAIFMT_CBS_CFS: /* cpu is master */ pcr = DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM | - DAVINCI_MCBSP_PCR_CLKXM | - DAVINCI_MCBSP_PCR_CLKRM; + DAVINCI_MCBSP_PCR_FSRM | + DAVINCI_MCBSP_PCR_CLKXM | + DAVINCI_MCBSP_PCR_CLKRM; break; case SND_SOC_DAIFMT_CBM_CFS: /* McBSP CLKR pin is the input for the Sample Rate Generator. * McBSP FSR and FSX are driven by the Sample Rate Generator. */ pcr = DAVINCI_MCBSP_PCR_SCLKME | - DAVINCI_MCBSP_PCR_FSXM | - DAVINCI_MCBSP_PCR_FSRM; + DAVINCI_MCBSP_PCR_FSXM | + DAVINCI_MCBSP_PCR_FSRM; break; case SND_SOC_DAIFMT_CBM_CFM: /* codec is master */ @@ -372,6 +391,17 @@ static int davinci_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, return 0; } +static int davinci_i2s_dai_set_clkdiv(struct snd_soc_dai *cpu_dai, + int div_id, int div) +{ + struct davinci_mcbsp_dev *dev = cpu_dai->private_data; + int srgr; + + mcbsp_data.clk_div = div; + return 0; +} + + static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -380,11 +410,12 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct davinci_pcm_dma_params *dma_params = &dev->dma_params[substream->stream]; struct snd_interval *i = NULL; - int mcbsp_word_length; - unsigned int rcr, xcr, srgr; + int mcbsp_word_length, master; + unsigned int rcr, xcr, srgr, clk_div, freq, framesize; u32 spcr; snd_pcm_format_t fmt; unsigned element_cnt = 1; + struct clk *clk; /* general line settings */ spcr = davinci_mcbsp_read_reg(dev, DAVINCI_MCBSP_SPCR_REG); @@ -396,12 +427,60 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SPCR_REG, spcr); } - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); - srgr = DAVINCI_MCBSP_SRGR_FSGM; - srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); + master = mcbsp_data.fmt & SND_SOC_DAIFMT_MASTER_MASK; + fmt = params_format(params); + mcbsp_word_length = asp_word_length[fmt]; - i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); - srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); + if (master == SND_SOC_DAIFMT_CBS_CFS) { + clk = clk_get(NULL, "pll1_sysclk6"); + if (clk) + freq = clk_get_rate(clk); + freq = 122000000; /* FIXME ask to Texas */ + if (dev->i2s_fast_clock) { + clk_div = 256; + do { + framesize = (freq / (--clk_div)) / + params->rate_num * + params->rate_den; + } while (((framesize < 33) || (framesize > 4095)) && + (clk_div)); + clk_div--; + srgr = DAVINCI_MCBSP_SRGR_FSGM | + DAVINCI_MCBSP_SRGR_CLKSM; + srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * + 8 - 1); + srgr |= DAVINCI_MCBSP_SRGR_FPER(framesize - 1); + } else { + /* simmetric waveforms */ + srgr = DAVINCI_MCBSP_SRGR_FSGM | + DAVINCI_MCBSP_SRGR_CLKSM; + srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * + 8 - 1); + srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * + 16 - 1); + clk_div = freq / (mcbsp_word_length * 16) / + params->rate_num * params->rate_den; + } + clk_div &= 0xFF; + srgr |= clk_div; + } else if (master == SND_SOC_DAIFMT_CBS_CFM) { + /* Clock given on CLKS */ + srgr = DAVINCI_MCBSP_SRGR_FSGM; + clk_div = mcbsp_data.clk_div - 1; + srgr |= DAVINCI_MCBSP_SRGR_FWID(mcbsp_word_length * 8 - 1); + srgr |= DAVINCI_MCBSP_SRGR_FPER(mcbsp_word_length * 16 - 1); + clk_div &= 0xFF; + srgr |= clk_div; + } else { + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); + srgr = DAVINCI_MCBSP_SRGR_FSGM; + srgr |= DAVINCI_MCBSP_SRGR_FWID(snd_interval_value(i) - 1); + pr_debug("%s - %d FWID set: re-read srgr = %X\n", + __func__, __LINE__, snd_interval_value(i) - 1); + + i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_FRAME_BITS); + srgr |= DAVINCI_MCBSP_SRGR_FPER(snd_interval_value(i) - 1); + } davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_SRGR_REG, srgr); rcr = DAVINCI_MCBSP_RCR_RFIG; @@ -426,22 +505,45 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, element_cnt = 1; fmt = double_fmt[fmt]; } + if (master == SND_SOC_DAIFMT_CBS_CFS || + master == SND_SOC_DAIFMT_CBS_CFM) { + rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(0); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(0); + rcr |= DAVINCI_MCBSP_RCR_RPHASE; + xcr |= DAVINCI_MCBSP_XCR_XPHASE; + } else { + /* FIXME ask to Texas */ + rcr |= DAVINCI_MCBSP_RCR_RFRLEN2(element_cnt - 1); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN2(element_cnt - 1); + } } dma_params->acnt = dma_params->data_type = data_type[fmt]; dma_params->fifo_level = 0; mcbsp_word_length = asp_word_length[fmt]; - rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); - xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); + + if (master == SND_SOC_DAIFMT_CBS_CFS || + master == SND_SOC_DAIFMT_CBS_CFM) { + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(0); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(0); + } else { + /* FIXME ask to Texas */ + rcr |= DAVINCI_MCBSP_RCR_RFRLEN1(element_cnt - 1); + xcr |= DAVINCI_MCBSP_XCR_XFRLEN1(element_cnt - 1); + } rcr |= DAVINCI_MCBSP_RCR_RWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); + DAVINCI_MCBSP_RCR_RWDLEN2(mcbsp_word_length); xcr |= DAVINCI_MCBSP_XCR_XWDLEN1(mcbsp_word_length) | - DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); + DAVINCI_MCBSP_XCR_XWDLEN2(mcbsp_word_length); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_XCR_REG, xcr); else davinci_mcbsp_write_reg(dev, DAVINCI_MCBSP_RCR_REG, rcr); + + pr_debug("%s - %d srgr=%X\n", __func__, __LINE__, srgr); + pr_debug("%s - %d xcr=%X\n", __func__, __LINE__, xcr); + pr_debug("%s - %d rcr=%X\n", __func__, __LINE__, rcr); return 0; } @@ -500,7 +602,7 @@ static struct snd_soc_dai_ops davinci_i2s_dai_ops = { .trigger = davinci_i2s_trigger, .hw_params = davinci_i2s_hw_params, .set_fmt = davinci_i2s_set_dai_fmt, - + .set_clkdiv = davinci_i2s_dai_set_clkdiv, }; struct snd_soc_dai davinci_i2s_dai = { @@ -548,6 +650,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) } if (pdata) { dev->enable_channel_combine = pdata->enable_channel_combine; + dev->i2s_fast_clock = pdata->i2s_fast_clock; dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].sram_size = pdata->sram_size_playback; dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].sram_size =