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); }
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); } }