예제 #1
0
파일: mmp-sspa.c 프로젝트: 3null/linux
/*
 * 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;
}
예제 #2
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;
}