int ux500_ab8500_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;
	unsigned int fmt, fmt_if1;
	int channels, ret = 0, slots, driver_mode;
	unsigned int codec_slot_width, cpu_slot_width;
	bool streamIsPlayback;

	pr_debug("%s: Enter\n", __func__);

	pr_debug("%s: substream->pcm->name = %s\n"
		"substream->pcm->id = %s.\n"
		"substream->name = %s.\n"
		"substream->number = %d.\n",
		__func__,
		substream->pcm->name,
		substream->pcm->id,
		substream->name,
		substream->number);

	channels = params_channels(params);

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S32_LE:
		cpu_slot_width = 32;
		break;

	default:
	case SNDRV_PCM_FORMAT_S16_LE:
		cpu_slot_width = 16;
		break;
	}

	/* Setup codec depending on driver-mode */
	driver_mode = (channels == 8) ?
		DRIVERMODE_CODEC_ONLY : DRIVERMODE_NORMAL;
	pr_debug("%s: Driver-mode: %s.\n",
		__func__,
		(driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY");

	ab8500_audio_set_bit_delay(codec_dai, 1);
	ux500_msp_dai_set_data_delay(cpu_dai, MSP_DELAY_1);

	if (driver_mode == DRIVERMODE_NORMAL) {
		codec_slot_width = cpu_slot_width;
		ab8500_audio_set_word_length(codec_dai, codec_slot_width);
		fmt = SND_SOC_DAIFMT_DSP_A |
			SND_SOC_DAIFMT_CBM_CFM |
			SND_SOC_DAIFMT_NB_NF |
			SND_SOC_DAIFMT_CONT;
	} else {
		codec_slot_width = 20;
		ab8500_audio_set_word_length(codec_dai, codec_slot_width);
		fmt = SND_SOC_DAIFMT_DSP_A |
			SND_SOC_DAIFMT_CBM_CFM |
			SND_SOC_DAIFMT_NB_NF |
			SND_SOC_DAIFMT_GATED;
	}

	ret = snd_soc_dai_set_fmt(codec_dai, fmt);
	if (ret < 0) {
		pr_err("%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n",
			__func__,
			ret);
		return ret;
	}

	ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
	if (ret < 0) {
		pr_err("%s: ERROR: snd_soc_dai_set_fmt for cpu_dai (ret = %d)!\n",
			__func__,
			ret);
		return ret;
	}

	/* Setup TDM-slots */
	streamIsPlayback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
	switch (channels) {
	case 1:
		slots = 8;
		tx_slots = (streamIsPlayback) ? TX_SLOT_MONO : 0;
		rx_slots = (streamIsPlayback) ? 0 : RX_SLOT_MONO;
		break;
	case 2:
		slots = 8;
		tx_slots = (streamIsPlayback) ? TX_SLOT_STEREO : 0;
		rx_slots = (streamIsPlayback) ? 0 : RX_SLOT_STEREO;
		break;
	case 8:
		slots = 8;
		tx_slots = (streamIsPlayback) ? TX_SLOT_8CH : 0;
		rx_slots = (streamIsPlayback) ? 0 : RX_SLOT_8CH;
		break;
	default:
		return -EINVAL;
	}

	pr_debug("%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n",
		__func__, tx_slots, rx_slots);
	ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots, cpu_slot_width);
	if (ret)
		return ret;

	pr_debug("%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n",
		__func__, tx_slots, rx_slots);
	ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots, codec_slot_width);
	if (ret)
		return ret;

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		pr_debug("%s: Setup IF1 for FM-radio.\n", __func__);
		fmt_if1 = SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_I2S;
		ret = ab8500_audio_setup_if1(codec_dai->codec, fmt_if1, 16, 1);
		if (ret)
			return ret;
	}

	return 0;
}
Example #2
0
int ux500_gen_msp0_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 *cpu_dai = rtd->cpu_dai;
	int channels = params_channels(params);
	int err = 0;

	pr_debug("%s: Enter.\n", __func__);
	pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name);
	pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id);
	pr_debug("%s: substream->name = %s.\n", __func__, substream->name);
	pr_debug("%s: substream->number = %d.\n", __func__, substream->number);
	pr_debug("%s: channels = %d.\n", __func__, channels);
	pr_debug("%s: DAI-index (Platform): %d\n", __func__, cpu_dai->id);

	if (channels != 1) {
		pr_err("%s: Only 1 channel.\n", __func__);
		err = -EINVAL;
		goto out_err;
	}

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		break;
	default:
		pr_err("%s: Only S16_LE.\n", __func__);
		err = -EINVAL;
		goto out_err;
	}

	err = snd_soc_dai_set_fmt(cpu_dai,
				SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBS_CFS |
				SND_SOC_DAIFMT_NB_NF);

	if (err) {
		pr_err("%s: snd_soc_dai_set_fmt(cpu_dai) failed with %d.\n",
			__func__,
			err);
		goto out_err;
	}

	err = snd_soc_dai_set_sysclk(cpu_dai,
		UX500_MSP_MASTER_CLOCK,
		19200000,
		0);

	if (err) {
		pr_err("%s: snd_soc_dai_set_sysclk(cpu_dai) failed with %d.\n",
			__func__, err);
		goto out_err;
	}

	err = snd_soc_dai_set_tdm_slot(cpu_dai, 0x1, 0x1, 1, 16);

	if (err) {
		pr_err("%s: cg29xx_set_tdm_slot(cpu_dai) failed with %d.\n",
			__func__,
			err);
		goto out_err;
	}
	ux500_msp_dai_set_data_delay(cpu_dai, MSP_DELAY_1);
out_err:
	return err;
}