/* * Set up the sspa dai format. The sspa port must be inactive * before calling this function as the physical * interface format is changed. */ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *sspa = sspa_priv->sspa; u32 sspa_sp, sspa_ctrl; /* check if we need to change anything at all */ if (sspa_priv->dai_fmt == fmt) return 0; /* we can only change the settings if the port is not in use */ if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) || (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) { dev_err(&sspa->pdev->dev, "can't change hardware dai format: stream is in use\n"); return -EINVAL; } /* reset port settings */ sspa_sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH; sspa_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: sspa_sp |= SSPA_SP_MSL; break; case SND_SOC_DAIFMT_CBM_CFM: break; default: return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: sspa_sp |= SSPA_SP_FSP; break; default: return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: sspa_sp |= SSPA_TXSP_FPER(63); sspa_sp |= SSPA_SP_FWID(31); sspa_ctrl |= SSPA_CTL_XDATDLY(1); break; default: return -EINVAL; } mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH); mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); /* * FIXME: hw issue, for the tx serial port, * can not config the master/slave mode; * so must clean this bit. * The master/slave mode has been set in the * rx port. */ sspa_sp &= ~SSPA_SP_MSL; mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl); mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl); /* Since we are configuring the timings for the format by hand * we have to defer some things until hw_params() where we * know parameters like the sample size. */ sspa_priv->dai_fmt = fmt; return 0; }
/* * Set up the sspa dai format. The sspa port must be inactive * before calling this function as the physical * interface format is changed. */ static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *sspa = sspa_priv->sspa; u32 sspa_sp, sspa_ctrl, sp_reg, ctrl_reg; if (cpu_dai->stream == SNDRV_PCM_STREAM_PLAYBACK) { sp_reg = SSPA_TXSP; ctrl_reg = SSPA_TXCTL; } else if (cpu_dai->stream == SNDRV_PCM_STREAM_CAPTURE) { sp_reg = SSPA_RXSP; ctrl_reg = SSPA_RXCTL; } else { /* don't configure anything */ return 0; } /* reset port settings */ sspa_sp = SSPA_SP_WEN | SSPA_SP_FIX; sspa_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBS_CFS: sspa_sp |= SSPA_SP_MSL; break; case SND_SOC_DAIFMT_CBM_CFM: break; default: return -EINVAL; } sspa_sp &= ~SSPA_SP_FSP; switch (fmt & SND_SOC_DAIFMT_INV_MASK) { case SND_SOC_DAIFMT_NB_NF: sspa_sp |= SSPA_SP_FSP; break; case SND_SOC_DAIFMT_NB_IF: break; default: return -EINVAL; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: sspa_sp |= SSPA_TXSP_FPER(63); sspa_sp |= SSPA_SP_FWID(31); sspa_ctrl |= SSPA_CTL_XDATDLY(1); sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS); /* fix to sample shift issue in I2S mode */ if (cpu_dai->stream == SNDRV_PCM_STREAM_PLAYBACK) sspa_sp |= SSPA_SP_FSP; break; case SND_SOC_DAIFMT_DSP_A: sspa_sp |= SSPA_TXSP_FPER(31); sspa_sp |= SSPA_SP_FWID(0); sspa_ctrl |= SSPA_CTL_XDATDLY(1); sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_16_BITS); break; case SND_SOC_DAIFMT_DSP_B: sspa_sp |= SSPA_TXSP_FPER(31); sspa_sp |= SSPA_SP_FWID(0); sspa_ctrl |= SSPA_CTL_XDATDLY(0); sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_16_BITS); break; default: return -EINVAL; } mmp_sspa_write_reg(sspa, sp_reg, sspa_sp); mmp_sspa_write_reg(sspa, ctrl_reg, sspa_ctrl); return 0; }