Exemplo n.º 1
0
static void cpcap_audio_configure_codec(struct cpcap_audio_state *state,
				struct cpcap_audio_state *prev)
{
	unsigned int temp_codec_rate = state->codec_rate;
	struct cpcap_regacc cdai_changes = { 0 };
	struct cpcap_regacc codec_changes = { 0 };
	int codec_freq_config = 0;

	const unsigned int CODEC_FREQ_MASK = CPCAP_BIT_CDC_CLK0
		| CPCAP_BIT_CDC_CLK1 | CPCAP_BIT_CDC_CLK2;
	const unsigned int CODEC_RESET_FREQ_MASK = CODEC_FREQ_MASK
		| CPCAP_BIT_CDC_CLOCK_TREE_RESET;

	static unsigned int prev_codec_data = 0x0, prev_cdai_data = 0x0;

	if (!is_codec_changed(state, prev))
		return;

	if (state->rat_type == CPCAP_AUDIO_RAT_CDMA)
		codec_freq_config = (CPCAP_BIT_CDC_CLK0
				| CPCAP_BIT_CDC_CLK1) ; /* 19.2Mhz */
	else
		codec_freq_config = CPCAP_BIT_CDC_CLK2 ; /* 26Mhz */

	/* If a codec is already in use, reset codec to initial state */
	if (prev->codec_mode != CPCAP_AUDIO_CODEC_OFF) {
		codec_changes.mask = prev_codec_data
			| CPCAP_BIT_DF_RESET
			| CPCAP_BIT_CDC_CLOCK_TREE_RESET;

		logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
			codec_changes.value, codec_changes.mask);

		prev_codec_data = 0;
		prev->codec_mode = CPCAP_AUDIO_CODEC_OFF;
	}

	temp_codec_rate &= 0x0000000F;
	temp_codec_rate = temp_codec_rate << 9;

	switch (state->codec_mode) {
	case CPCAP_AUDIO_CODEC_LOOPBACK:
	case CPCAP_AUDIO_CODEC_ON:
		if (state->codec_primary_speaker !=
			CPCAP_AUDIO_OUT_NONE) {
			codec_changes.value |= CPCAP_BIT_CDC_EN_RX;
		}

		/* Turning on the input HPF */
		if (state->microphone != CPCAP_AUDIO_IN_NONE)
			codec_changes.value |= CPCAP_BIT_AUDIHPF_0 |
						CPCAP_BIT_AUDIHPF_1;

#if 1
		if (state->microphone != CPCAP_AUDIO_IN_NONE) {
			codec_changes.value |= CPCAP_BIT_MIC1_CDC_EN;
			codec_changes.value |= CPCAP_BIT_MIC2_CDC_EN;
		}
#else
		if (state->microphone != CPCAP_AUDIO_IN_AUX_INTERNAL &&
			state->microphone != CPCAP_AUDIO_IN_NONE)
			codec_changes.value |= CPCAP_BIT_MIC1_CDC_EN |
						CPCAP_BIT_MIC2_CDC_EN;

		if (state->microphone == CPCAP_AUDIO_IN_AUX_INTERNAL ||
			is_mic_stereo(state->microphone))
			codec_changes.value |= CPCAP_BIT_MIC2_CDC_EN;
#endif

	/* falling through intentionally */
	case CPCAP_AUDIO_CODEC_CLOCK_ONLY:
		codec_changes.value |=
			(codec_freq_config | temp_codec_rate |
			CPCAP_BIT_DF_RESET);
		cdai_changes.value |= CPCAP_BIT_CDC_CLK_EN;
		break;

	case CPCAP_AUDIO_CODEC_OFF:
		cdai_changes.value |= CPCAP_BIT_SMB_CDC;
		break;

	default:
		break;
	}

	/* Multimedia uses CLK_IN0, incall uses CLK_IN1 */
	if (state->rat_type != CPCAP_AUDIO_RAT_NONE)
		cdai_changes.value |= CPCAP_BIT_CLK_IN_SEL;

	cdai_changes.value |= CPCAP_BIT_CDC_PLL_SEL;
#if 0
	cdai_changes.value |= CPCAP_BIT_DIG_AUD_IN;
#endif

#ifdef CODEC_IS_I2S_MODE
	cdai_changes.value |= CPCAP_BIT_CLK_INV;
	/* Setting I2S mode */
	cdai_changes.value |= CPCAP_BIT_CDC_DIG_AUD_FS0 |
			CPCAP_BIT_CDC_DIG_AUD_FS1 |
			CPCAP_BIT_MIC2_TIMESLOT0;
#else
	/* Setting CODEC mode */
	/* FS:  Not inverted.
	 * Clk: Not inverted.
	 * TS2/TS1/TS0 not set, using timeslot 0 for mic1.
	 */
	cdai_changes.value |= CPCAP_BIT_CDC_DIG_AUD_FS0;
#endif

	/* OK, now start paranoid codec sequence */
	/* FIRST, make sure the frequency config is right... */
	logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
				codec_freq_config, CODEC_FREQ_MASK);

	/* Next, write the CDAI if it's changed */
	if (prev_cdai_data != cdai_changes.value) {
		cdai_changes.mask = cdai_changes.value
			| prev_cdai_data;
		prev_cdai_data = cdai_changes.value;

		logged_cpcap_write(state->cpcap, CPCAP_REG_CDI,
				cdai_changes.value, cdai_changes.mask);

		/* Clock tree change -- reset and wait */
		codec_freq_config |= CPCAP_BIT_CDC_CLOCK_TREE_RESET;

		logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
			codec_freq_config, CODEC_RESET_FREQ_MASK);

		/* Wait for clock tree reset to complete */
		mdelay(CLOCK_TREE_RESET_DELAY_MS);
	}

	/* Clear old settings */
	codec_changes.mask = codec_changes.value | prev_codec_data;
	prev_codec_data    = codec_changes.value;

	logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
			codec_changes.value, codec_changes.mask);
}
Exemplo n.º 2
0
static void cpcap_audio_configure_codec(struct cpcap_audio_state *state,
				struct cpcap_audio_state *previous_state) {
	const unsigned int CODEC_FREQ_MASK = CPCAP_BIT_CDC_CLK0
		| CPCAP_BIT_CDC_CLK1 | CPCAP_BIT_CDC_CLK2;
	const unsigned int CODEC_RESET_FREQ_MASK = CODEC_FREQ_MASK
		| CPCAP_BIT_CDC_CLOCK_TREE_RESET;

	static unsigned int prev_codec_data = 0x0, prev_cdai_data = 0x0;

	if (is_codec_changed(state, previous_state)) {
		unsigned int temp_codec_rate = state->codec_rate;
		struct cpcap_regacc cdai_changes = { 0 };
		struct cpcap_regacc codec_changes = { 0 };
		int codec_freq_config = 0;

		if (state->rat_type == CPCAP_AUDIO_RAT_CDMA)
			codec_freq_config = (CPCAP_BIT_CDC_CLK0
					| CPCAP_BIT_CDC_CLK1) ; /* 19.2Mhz */
		else
			codec_freq_config = CPCAP_BIT_CDC_CLK2 ; /* 26Mhz */

		/* If a codec is already in use, reset codec to initial state */
		/* TODO: optimize - make less paranoid according to TI recs */
		if (previous_state->codec_mode != CPCAP_AUDIO_CODEC_OFF) {
			codec_changes.mask = prev_codec_data
				| CPCAP_BIT_DF_RESET
				| CPCAP_BIT_CDC_CLOCK_TREE_RESET;

			logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
				codec_changes.value, codec_changes.mask);

			prev_codec_data = 0;
			previous_state->codec_mode = CPCAP_AUDIO_CODEC_OFF;
		}

		temp_codec_rate &= 0x0000000F;
		temp_codec_rate = temp_codec_rate << 9;

		switch (state->codec_mode) {
		case CPCAP_AUDIO_CODEC_LOOPBACK:
		case CPCAP_AUDIO_CODEC_ON:
			if (state->codec_primary_speaker !=
						CPCAP_AUDIO_OUT_NONE)
				codec_changes.value |= CPCAP_BIT_CDC_EN_RX;

			/* Turning on the input HPF */
			if (state->microphone != CPCAP_AUDIO_IN_NONE)
				codec_changes.value |= CPCAP_BIT_AUDIHPF_0 |
							CPCAP_BIT_AUDIHPF_1;

			if (state->microphone != CPCAP_AUDIO_IN_AUX_INTERNAL &&
				state->microphone != CPCAP_AUDIO_IN_NONE)
				codec_changes.value |= CPCAP_BIT_MIC1_CDC_EN;

			if (state->microphone == CPCAP_AUDIO_IN_AUX_INTERNAL ||
				is_mic_stereo(state->microphone))
				codec_changes.value |= CPCAP_BIT_MIC2_CDC_EN;

		/* falling through intentionally */
		case CPCAP_AUDIO_CODEC_CLOCK_ONLY:
			codec_changes.value |=
				(codec_freq_config | temp_codec_rate |
				CPCAP_BIT_DF_RESET);
			cdai_changes.value |= CPCAP_BIT_CDC_CLK_EN;
			break;

		case CPCAP_AUDIO_CODEC_OFF:
			cdai_changes.value |= CPCAP_BIT_SMB_CDC;
			break;

		default:
			break;
		}

		/* Multimedia uses CLK_IN0, incall uses CLK_IN1 */
		if (state->rat_type != CPCAP_AUDIO_RAT_NONE)
			cdai_changes.value |= CPCAP_BIT_CLK_IN_SEL;

		/* UMTS sholes uses Network mode - 4 time slots
		-Codec is Master of Fsync Bclk
		-CODEC uses DAI0
		-CODEC PLL to be used */
		cdai_changes.value |= (CPCAP_BIT_CDC_DIG_AUD_FS0 |
						CPCAP_BIT_CDC_PLL_SEL);

		if ((state->rat_type == CPCAP_AUDIO_RAT_NONE) &&
			(state->microphone == CPCAP_AUDIO_IN_AUX_INTERNAL))
			cdai_changes.value |= CPCAP_BIT_MIC1_RX_TIMESLOT0;
		else
			cdai_changes.value |= CPCAP_BIT_MIC2_TIMESLOT0;

		/* OK, now start paranoid codec sequence */
		/* TODO: optimize - make less paranoid */
		/* FIRST, make sure the frequency config is right... */
		logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
			codec_freq_config, CODEC_FREQ_MASK);

		/* Next, write the CDAI if it's changed */
		if (prev_cdai_data != cdai_changes.value) {
			cdai_changes.mask = cdai_changes.value
				| prev_cdai_data;
			prev_cdai_data = cdai_changes.value;

			logged_cpcap_write(state->cpcap,
				CPCAP_REG_CDI, cdai_changes.value,
				cdai_changes.mask);

			/* Clock tree change -- reset and wait */
			codec_freq_config |= CPCAP_BIT_CDC_CLOCK_TREE_RESET;
			logged_cpcap_write(state->cpcap,
					CPCAP_REG_CC,
					codec_freq_config,
					CODEC_RESET_FREQ_MASK);

			/* Wait for clock tree reset to complete */
			mdelay(CLOCK_TREE_RESET_TIME);
		}

		/* Clear old settings */
		codec_changes.mask = codec_changes.value | prev_codec_data;
		prev_codec_data    = codec_changes.value;

		logged_cpcap_write(state->cpcap, CPCAP_REG_CC,
			codec_changes.value, codec_changes.mask);
	}
}