From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dong Aisheng Subject: Re: [PATCH 02/10] ASoc: mxs: add mxs-saif driver Date: Sun, 10 Jul 2011 16:17:13 +0800 Message-ID: References: <1310140790-2132-1-git-send-email-b29396@freescale.com> <1310140790-2132-3-git-send-email-b29396@freescale.com> <20110709025252.GC26900@sirena.org.uk> Mime-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Return-path: In-Reply-To: <20110709025252.GC26900@sirena.org.uk> List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=m.gmane.org@lists.infradead.org To: Mark Brown Cc: alsa-devel@alsa-project.org, Dong Aisheng , s.hauer@pengutronix.de, linux-arm-kernel@lists.infradead.org, lrg@ti.com List-Id: alsa-devel@alsa-project.org 2011/7/9 Mark Brown : > On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote: >> Signed-off-by: Dong Aisheng > > Again, *always* CC maintainers on patches. Will add in the updated patch. >> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int clk_id, unsigned int freq,= int dir) >> +{ >> + =A0 =A0 struct mxs_saif *saif =3D snd_soc_dai_get_drvdata(cpu_dai); >> + >> + =A0 =A0 switch (clk_id) { >> + =A0 =A0 case MXS_SAIF_SYS_CLK: >> + =A0 =A0 =A0 =A0 =A0 =A0 clk_set_rate(saif->clk, freq); >> + =A0 =A0 =A0 =A0 =A0 =A0 clk_enable(saif->clk); > > How would one turn this clock off? Currenty simply enable clock always. The problem is that the codec may use the MCLK supplied by SAIF as its system clock for normal operations such as i2c r/w. If we disable it after playback or capture. The automatic dapm operations of codec may fail on i2c r/w. Will check if dapm has any machnism to avoid this. Can you share your experience ont this issue? >> + * SAIF Clock dividers >> + * Should only be called when port is inactive. >> + */ >> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int div_id= , int div) >> +{ >> + =A0 =A0 u32 scr; >> + =A0 =A0 struct mxs_saif *saif =3D snd_soc_dai_get_drvdata(cpu_dai); >> + >> + =A0 =A0 scr =3D __raw_readl(saif->base + SAIF_CTRL); >> + =A0 =A0 scr &=3D ~BM_SAIF_CTRL_BITCLK_MULT_RATE; >> + =A0 =A0 scr &=3D ~BM_SAIF_CTRL_BITCLK_BASE_RATE; >> + >> + =A0 =A0 switch (div_id) { >> + =A0 =A0 case MXS_SAIF_MCLK: >> + =A0 =A0 =A0 =A0 =A0 =A0 switch (div) { >> + =A0 =A0 =A0 =A0 =A0 =A0 case 32: > > No, this stuff should all be figured out automatically by the driver - > the user shouldn't have to manually set the ratio, especially if they've > already set the master clock. Yes, that's a good point and i will try to do it in the updated patch. >> + =A0 =A0 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { >> + =A0 =A0 case SND_SOC_DAIFMT_I2S: >> + =A0 =A0 =A0 =A0 =A0 =A0 /* data frame low 1clk before data */ >> + =A0 =A0 =A0 =A0 =A0 =A0 scr |=3D BM_SAIF_CTRL_DELAY; >> + =A0 =A0 =A0 =A0 =A0 =A0 scr &=3D ~BM_SAIF_CTRL_LRCLK_POLARITY; >> + =A0 =A0 =A0 =A0 =A0 =A0 break; >> + =A0 =A0 case SND_SOC_DAIFMT_LEFT_J: >> + =A0 =A0 =A0 =A0 =A0 =A0 /* data frame high with data */ >> + =A0 =A0 =A0 =A0 =A0 =A0 scr &=3D ~BM_SAIF_CTRL_DELAY; >> + =A0 =A0 =A0 =A0 =A0 =A0 scr &=3D ~BM_SAIF_CTRL_LRCLK_POLARITY; >> + =A0 =A0 =A0 =A0 =A0 =A0 scr &=3D ~BM_SAIF_CTRL_JUSTIFY; >> + =A0 =A0 =A0 =A0 =A0 =A0 break; >> + =A0 =A0 } > > This should return an error if the parameters are invalid. =A0The rest of > the code has many other instances of this missing check. Will add them. >> + =A0 =A0 /* >> + =A0 =A0 =A0* Note: We simply just support master mode since SAIF TX on= ly supports >> + =A0 =A0 =A0* master mode. >> + =A0 =A0 =A0*/ >> + =A0 =A0 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { >> + =A0 =A0 case SND_SOC_DAIFMT_CBS_CFS: >> + =A0 =A0 =A0 =A0 =A0 =A0 scr &=3D ~BM_SAIF_CTRL_SLAVE_MODE; >> + =A0 =A0 =A0 =A0 =A0 =A0 __raw_writel(scr | scr0, saif->base + SAIF_CTR= L); >> + =A0 =A0 =A0 =A0 =A0 =A0 break; >> + =A0 =A0 case SND_SOC_DAIFMT_CBM_CFS: >> + =A0 =A0 =A0 =A0 =A0 =A0 break; >> + =A0 =A0 case SND_SOC_DAIFMT_CBS_CFM: >> + =A0 =A0 =A0 =A0 =A0 =A0 break; > > This is clearly wrong, you're doing exactly the same thing for two > different inputs. Will fix in next patch. >> +static int mxs_saif_startup(struct snd_pcm_substream *substream, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai *cpu= _dai) >> +{ >> + =A0 =A0 struct mxs_saif *saif =3D snd_soc_dai_get_drvdata(cpu_dai); >> + =A0 =A0 snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param); >> + >> + =A0 =A0 return 0; >> +} > > Remove empty functions. This is to set dma param. >> +/* >> + * Should only be called when port is inactive. >> + * although can be called multiple times by upper layers. >> + */ >> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_pcm_hw_p= arams *params, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0struct snd_soc_dai = *cpu_dai) > > The requirement for the port to be inactive is totally unreasonable, > especially given that the params are configured by applications and you > support simultaneous playback and record. Yes, i will remove it. Finally we will support simultaneous playback and re= cord. >> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id) >> +{ >> + =A0 =A0 struct mxs_saif *saif =3D dev_id; >> + >> + =A0 =A0 if (saif->fifo_err_counter++ % 100 =3D=3D 0) > > The rate limit looks awfully suspicious... Originally it's just for printing less error messages when the issue happen= s. I could remove the rate limit. >> + =A0 =A0 =A0 =A0 =A0 =A0 printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CT= RL %x \ >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 fifo_errs=3D%d \n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__raw_readl(saif->base + SAIF_S= TAT), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0__raw_readl(saif->base + SAIF_C= TRL), >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0saif->fifo_err_counter); > > dev_err() Will change. >> + =A0 =A0 __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ | >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 BM_SAIF_STAT_FIFO_OVERFLOW_IRQ, >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 saif->base + SAIF_STAT + MXS_C= LR_ADDR); >> + >> + =A0 =A0 return IRQ_HANDLED; > > You're not actually checking that the relevant interrupt fired... I will add the checking for different errors. >> + =A0 =A0 saif->clk =3D clk_get(&pdev->dev, NULL); >> + =A0 =A0 if (IS_ERR(saif->clk)) { >> + =A0 =A0 =A0 =A0 =A0 =A0 ret =3D PTR_ERR(saif->clk); >> + =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&pdev->dev, "Cannot get the clock: %d\= n", >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret); >> + =A0 =A0 =A0 =A0 =A0 =A0 goto failed_clk; >> + =A0 =A0 } >> + =A0 =A0 clk_set_rate(saif->clk, 12000000); >> + =A0 =A0 clk_enable(saif->clk); > > How did you pick this clock rate and why does it need to be set? =A0It's > not an obvious audio rate... It's initial clock rate for normal operations of codecs based on MCLK. We found the default MCLK ouput(only about 7.3Khz) can not work for codecs = like sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz. So we set a common working clock 12Mhz here. Maybe i should try to set it elsewhere or just set it via platform data. > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel > From mboxrd@z Thu Jan 1 00:00:00 1970 From: dongas86@gmail.com (Dong Aisheng) Date: Sun, 10 Jul 2011 16:17:13 +0800 Subject: [PATCH 02/10] ASoc: mxs: add mxs-saif driver In-Reply-To: <20110709025252.GC26900@sirena.org.uk> References: <1310140790-2132-1-git-send-email-b29396@freescale.com> <1310140790-2132-3-git-send-email-b29396@freescale.com> <20110709025252.GC26900@sirena.org.uk> Message-ID: To: linux-arm-kernel@lists.infradead.org List-Id: linux-arm-kernel.lists.infradead.org 2011/7/9 Mark Brown : > On Fri, Jul 08, 2011 at 11:59:42PM +0800, Dong Aisheng wrote: >> Signed-off-by: Dong Aisheng > > Again, *always* CC maintainers on patches. Will add in the updated patch. >> +static int mxs_saif_set_dai_sysclk(struct snd_soc_dai *cpu_dai, >> + ? ? ? ? ? ? ? ? ? ? int clk_id, unsigned int freq, int dir) >> +{ >> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); >> + >> + ? ? switch (clk_id) { >> + ? ? case MXS_SAIF_SYS_CLK: >> + ? ? ? ? ? ? clk_set_rate(saif->clk, freq); >> + ? ? ? ? ? ? clk_enable(saif->clk); > > How would one turn this clock off? Currenty simply enable clock always. The problem is that the codec may use the MCLK supplied by SAIF as its system clock for normal operations such as i2c r/w. If we disable it after playback or capture. The automatic dapm operations of codec may fail on i2c r/w. Will check if dapm has any machnism to avoid this. Can you share your experience ont this issue? >> + * SAIF Clock dividers >> + * Should only be called when port is inactive. >> + */ >> +static int mxs_saif_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, >> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? int div_id, int div) >> +{ >> + ? ? u32 scr; >> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); >> + >> + ? ? scr = __raw_readl(saif->base + SAIF_CTRL); >> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_MULT_RATE; >> + ? ? scr &= ~BM_SAIF_CTRL_BITCLK_BASE_RATE; >> + >> + ? ? switch (div_id) { >> + ? ? case MXS_SAIF_MCLK: >> + ? ? ? ? ? ? switch (div) { >> + ? ? ? ? ? ? case 32: > > No, this stuff should all be figured out automatically by the driver - > the user shouldn't have to manually set the ratio, especially if they've > already set the master clock. Yes, that's a good point and i will try to do it in the updated patch. >> + ? ? switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { >> + ? ? case SND_SOC_DAIFMT_I2S: >> + ? ? ? ? ? ? /* data frame low 1clk before data */ >> + ? ? ? ? ? ? scr |= BM_SAIF_CTRL_DELAY; >> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY; >> + ? ? ? ? ? ? break; >> + ? ? case SND_SOC_DAIFMT_LEFT_J: >> + ? ? ? ? ? ? /* data frame high with data */ >> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_DELAY; >> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_LRCLK_POLARITY; >> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_JUSTIFY; >> + ? ? ? ? ? ? break; >> + ? ? } > > This should return an error if the parameters are invalid. ?The rest of > the code has many other instances of this missing check. Will add them. >> + ? ? /* >> + ? ? ?* Note: We simply just support master mode since SAIF TX only supports >> + ? ? ?* master mode. >> + ? ? ?*/ >> + ? ? switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { >> + ? ? case SND_SOC_DAIFMT_CBS_CFS: >> + ? ? ? ? ? ? scr &= ~BM_SAIF_CTRL_SLAVE_MODE; >> + ? ? ? ? ? ? __raw_writel(scr | scr0, saif->base + SAIF_CTRL); >> + ? ? ? ? ? ? break; >> + ? ? case SND_SOC_DAIFMT_CBM_CFS: >> + ? ? ? ? ? ? break; >> + ? ? case SND_SOC_DAIFMT_CBS_CFM: >> + ? ? ? ? ? ? break; > > This is clearly wrong, you're doing exactly the same thing for two > different inputs. Will fix in next patch. >> +static int mxs_saif_startup(struct snd_pcm_substream *substream, >> + ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai) >> +{ >> + ? ? struct mxs_saif *saif = snd_soc_dai_get_drvdata(cpu_dai); >> + ? ? snd_soc_dai_set_dma_data(cpu_dai, substream, &saif->dma_param); >> + >> + ? ? return 0; >> +} > > Remove empty functions. This is to set dma param. >> +/* >> + * Should only be called when port is inactive. >> + * although can be called multiple times by upper layers. >> + */ >> +static int mxs_saif_hw_params(struct snd_pcm_substream *substream, >> + ? ? ? ? ? ? ? ? ? ? ? ? ?struct snd_pcm_hw_params *params, >> + ? ? ? ? ? ? ? ? ? ? ? ? ?struct snd_soc_dai *cpu_dai) > > The requirement for the port to be inactive is totally unreasonable, > especially given that the params are configured by applications and you > support simultaneous playback and record. Yes, i will remove it. Finally we will support simultaneous playback and record. >> +static irqreturn_t mxs_saif_irq(int irq, void *dev_id) >> +{ >> + ? ? struct mxs_saif *saif = dev_id; >> + >> + ? ? if (saif->fifo_err_counter++ % 100 == 0) > > The rate limit looks awfully suspicious... Originally it's just for printing less error messages when the issue happens. I could remove the rate limit. >> + ? ? ? ? ? ? printk(KERN_ERR "saif_irq SAIF_STAT %x SAIF_CTRL %x \ >> + ? ? ? ? ? ? ? ? ? ? fifo_errs=%d \n", >> + ? ? ? ? ? ? ? ? ? ?__raw_readl(saif->base + SAIF_STAT), >> + ? ? ? ? ? ? ? ? ? ?__raw_readl(saif->base + SAIF_CTRL), >> + ? ? ? ? ? ? ? ? ? ?saif->fifo_err_counter); > > dev_err() Will change. >> + ? ? __raw_writel(BM_SAIF_STAT_FIFO_UNDERFLOW_IRQ | >> + ? ? ? ? ? ? ? ? ? ? BM_SAIF_STAT_FIFO_OVERFLOW_IRQ, >> + ? ? ? ? ? ? ? ? ? ? saif->base + SAIF_STAT + MXS_CLR_ADDR); >> + >> + ? ? return IRQ_HANDLED; > > You're not actually checking that the relevant interrupt fired... I will add the checking for different errors. >> + ? ? saif->clk = clk_get(&pdev->dev, NULL); >> + ? ? if (IS_ERR(saif->clk)) { >> + ? ? ? ? ? ? ret = PTR_ERR(saif->clk); >> + ? ? ? ? ? ? dev_err(&pdev->dev, "Cannot get the clock: %d\n", >> + ? ? ? ? ? ? ? ? ? ? ret); >> + ? ? ? ? ? ? goto failed_clk; >> + ? ? } >> + ? ? clk_set_rate(saif->clk, 12000000); >> + ? ? clk_enable(saif->clk); > > How did you pick this clock rate and why does it need to be set? ?It's > not an obvious audio rate... It's initial clock rate for normal operations of codecs based on MCLK. We found the default MCLK ouput(only about 7.3Khz) can not work for codecs like sgtl5000 for its initialization since its clock range is 8Mhz~27Mhz. So we set a common working clock 12Mhz here. Maybe i should try to set it elsewhere or just set it via platform data. > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel >