static void cpcap_audio_configure_output_gains( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { if (state->output_gain != previous_state->output_gain || state->fm_output_gain != previous_state->fm_output_gain || state->rat_type != previous_state->rat_type) { struct cpcap_regacc reg_changes = { 0 }; unsigned int temp_output_gain = state->output_gain & 0x0000000F; unsigned int temp_fm_gain = state->fm_output_gain & 0x0000000F; reg_changes.value |= ((temp_output_gain << 2) | (temp_output_gain << 8)); if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) { /*voice gain for analog downlink -- not needed for * for Droid WE (CDMA I2S downlink)*/ reg_changes.value |= (temp_output_gain << 12); } else { reg_changes.value |= (temp_fm_gain << 12); } reg_changes.mask = 0xFF3C; logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, reg_changes.value, reg_changes.mask); } }
static void cpcap_audio_configure_analog_source( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { if (state->analog_source != previous_state->analog_source) { struct cpcap_regacc ext_changes = { 0 }; static unsigned int prev_ext_data; switch (state->analog_source) { case CPCAP_AUDIO_ANALOG_SOURCE_STEREO: ext_changes.value |= CPCAP_BIT_MONO_EXT0 | CPCAP_BIT_PGA_IN_R_SW | CPCAP_BIT_PGA_IN_L_SW; break; case CPCAP_AUDIO_ANALOG_SOURCE_L: ext_changes.value |= CPCAP_BIT_MONO_EXT1 | CPCAP_BIT_PGA_IN_L_SW; break; case CPCAP_AUDIO_ANALOG_SOURCE_R: ext_changes.value |= CPCAP_BIT_MONO_EXT1 | CPCAP_BIT_PGA_IN_R_SW; break; default: break; } ext_changes.mask = ext_changes.value | prev_ext_data; prev_ext_data = ext_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, ext_changes.value, ext_changes.mask); } }
static void cpcap_audio_configure_aud_mute(struct cpcap_audio_state *state, struct cpcap_audio_state *prev_state) { struct cpcap_regacc reg_changes = { 0 }; unsigned short int value1 = 0, value2 = 0; if (state->codec_mute != prev_state->codec_mute) { value1 = cpcap_audio_get_codec_output_amp_switches( prev_state->codec_primary_speaker, prev_state->codec_primary_balance); value2 = cpcap_audio_get_codec_output_amp_switches( prev_state->codec_secondary_speaker, prev_state->codec_primary_balance); reg_changes.mask = value1 | value2 | CPCAP_BIT_CDC_SW; if (state->codec_mute == CPCAP_AUDIO_CODEC_UNMUTE) reg_changes.value = reg_changes.mask; logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, reg_changes.value, reg_changes.mask); } if (state->stdac_mute != prev_state->stdac_mute) { value1 = cpcap_audio_get_stdac_output_amp_switches( prev_state->stdac_primary_speaker, prev_state->stdac_primary_balance); value2 = cpcap_audio_get_stdac_output_amp_switches( prev_state->stdac_secondary_speaker, prev_state->stdac_primary_balance); reg_changes.mask = value1 | value2 | CPCAP_BIT_ST_DAC_SW; if (state->stdac_mute == CPCAP_AUDIO_STDAC_UNMUTE) reg_changes.value = reg_changes.mask; logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, reg_changes.value, reg_changes.mask); } /*hack*/ logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA,0x1e02,0x1FFF ); }
static void cpcap_audio_configure_output( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { static unsigned int prev_aud_out_data; if (is_output_changed(previous_state, state) || is_codec_changed(previous_state, state) || is_stdac_changed(previous_state, state)) { bool activate_ext_loudspeaker = false; struct cpcap_regacc reg_changes = { 0 }; cpcap_audio_set_output_amp_switches(state); activate_ext_loudspeaker = cpcap_audio_set_bits_for_speaker( state->codec_primary_speaker, state->codec_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->codec_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->stdac_primary_speaker, state->stdac_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->stdac_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->ext_primary_speaker, state->ext_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->ext_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); reg_changes.mask = reg_changes.value | prev_aud_out_data; prev_aud_out_data = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, reg_changes.value, reg_changes.mask); } }
static void cpcap_audio_configure_input_gains( struct cpcap_audio_state *state, struct cpcap_audio_state *prev) { if (state->input_gain != prev->input_gain) { struct cpcap_regacc reg_changes = { 0 }; unsigned int temp_input_gain = state->input_gain & 0x0000001F; reg_changes.value |= ((temp_input_gain << 5) | temp_input_gain); reg_changes.mask = 0x3FF; logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, reg_changes.value, reg_changes.mask); } }
static void cpcap_audio_configure_input_gains( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { if (state->input_gain_r != previous_state->input_gain_r || state->input_gain_l != previous_state->input_gain_l) { struct cpcap_regacc reg_changes = { 0 }; reg_changes.value = state->input_gain_r & 0x1F; reg_changes.value |= ((state->input_gain_l & 0x1F) << 5); reg_changes.mask = 0x3FF; logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, reg_changes.value, reg_changes.mask); } }
static void cpcap_audio_configure_input( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { static unsigned int prev_input_data = 0x0; struct cpcap_regacc reg_changes = { 0 }; if (state->microphone != previous_state->microphone || CODEC_LOOPBACK_CHANGED()) { if (state->codec_mode == CPCAP_AUDIO_CODEC_LOOPBACK) reg_changes.value |= CPCAP_BIT_DLM; if ((state->microphone & CPCAP_AUDIO_IN_DUAL_EXTERNAL) != 0) { reg_changes.value |= CPCAP_BIT_RX_R_ENCODE | CPCAP_BIT_RX_L_ENCODE; } else { /*HANDSET and HEADSET mics are mutually exclusive. *if both are selected, HANDSET will win */ if ((state->microphone & CPCAP_AUDIO_IN_HANDSET) != 0) { reg_changes.value |= CPCAP_BIT_MB_ON1R | CPCAP_BIT_MIC1_MUX | CPCAP_BIT_MIC1_PGA_EN; } else if ((state->microphone & CPCAP_AUDIO_IN_HEADSET) != 0) { reg_changes.value |= CPCAP_BIT_HS_MIC_MUX | CPCAP_BIT_MIC1_PGA_EN; } /*NOTE an implementation quirk: SECONDARY and TERTIARY * are equivalent on 2-mic hardware. * This is unintentional but harmless */ if (needs_cpcap_mic2(state->microphone)) { reg_changes.value |= CPCAP_BIT_MB_ON1L | CPCAP_BIT_MIC2_MUX | CPCAP_BIT_MIC2_PGA_EN; } } reg_changes.mask = reg_changes.value | prev_input_data; prev_input_data = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, reg_changes.value, reg_changes.mask); } }
static void cpcap_audio_configure_output_gains( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { if (state->output_gain != previous_state->output_gain) { struct cpcap_regacc reg_changes = { 0 }; unsigned int temp_output_gain = state->output_gain & 0x0000000F; reg_changes.value |= ((temp_output_gain << 2) | (temp_output_gain << 8) | (temp_output_gain << 12)); reg_changes.mask = 0xFF3C; logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, reg_changes.value, reg_changes.mask); } }
static void cpcap_audio_configure_output_gains( struct cpcap_audio_state *state, struct cpcap_audio_state *prev) { if (state->output_gain != prev->output_gain) { struct cpcap_regacc reg_changes = { 0 }; unsigned int temp_output_gain = state->output_gain & 0x0000000F; reg_changes.value |= ((temp_output_gain << 2) | (temp_output_gain << 8)); /* VOL_EXTx is disabled, it's not connected, disable to reduce * noise. If you need it, add | (temp_output_gain << 12) */ reg_changes.mask = 0xFF3C; logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, reg_changes.value, reg_changes.mask); } }
void cpcap_audio_init(struct cpcap_audio_state *state) { CPCAP_AUDIO_DEBUG_LOG("%s() called\n", __func__); logged_cpcap_write(state->cpcap, CPCAP_REG_CC, 0, 0xFFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_CDI, 0, 0xBFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, 0, 0xFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, 0, 0x3FFF); logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, 0, 0xFDF); logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, 0, 0xFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, 0, 0x1FF); /* logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, 0, 0xFFF); */ logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, 0, 0x7FF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, 0, 0x1FFF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, 0, 0x7FFF); /* The problem which speaker noise generated when phone enter the suspend mode is fixed. */ logged_cpcap_write(state->cpcap, CPCAP_REG_A2LA, CPCAP_BIT_A2_FREE_RUN, CPCAP_BIT_A2_FREE_RUN); #if !defined(CONFIG_MACH_SHOLEST) logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, CPCAP_BIT_GPIO4DIR, CPCAP_BIT_GPIO4DIR); #endif /* !CONFIG_MACH_SHOLEST */ audio_reg = regulator_get(NULL, "vaudio"); if (IS_ERR(audio_reg)) CPCAP_AUDIO_ERROR_LOG("could not get regulator for audio\n"); }
void cpcap_audio_init(struct cpcap_audio_state *state) { CPCAP_AUDIO_DEBUG_LOG("%s() called\n", __func__); printk("%s() level 1\n",__func__); logged_cpcap_write(state->cpcap, CPCAP_REG_CC, 0, 0xFFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_CDI, 0, 0xBFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, 0, 0xFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, 0, 0x3FFF); logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, 0, 0xFDF); logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, 0, 0xFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, 0, 0x1FF); /* logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, 0, 0xFFF); */ logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, 0, 0x7FF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, 0, 0x1FFF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, 0, 0x7FFF); printk("%s() level 2\n",__func__); if (cpcap_audio_hw_has_hs_driver() || cpcap_audio_hw_has_mic3_switch()) logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, CPCAP_BIT_GPIO4DIR, CPCAP_BIT_GPIO4DIR); /*hack*/ printk("%s() level 3\n",__func__); logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA,0x1e02,0x1FFF ); audio_regu = regulator_get(NULL, "vaudio"); printk("%s() level 4\n",__func__); if (IS_ERR(audio_regu)) CPCAP_AUDIO_ERROR_LOG("could not get regulator for audio\n"); }
static void cpcap_audio_configure_stdac(struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { const unsigned int SDAC_FREQ_MASK = CPCAP_BIT_ST_DAC_CLK0 | CPCAP_BIT_ST_DAC_CLK1 | CPCAP_BIT_ST_DAC_CLK2; const unsigned int SDAC_RESET_FREQ_MASK = SDAC_FREQ_MASK | CPCAP_BIT_ST_CLOCK_TREE_RESET; static unsigned int prev_stdac_data, prev_sdai_data; if (is_stdac_changed(state, previous_state)) { unsigned int temp_stdac_rate = state->stdac_rate; struct cpcap_regacc sdai_changes = { 0 }; struct cpcap_regacc stdac_changes = { 0 }; int stdac_freq_config = 0; if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) stdac_freq_config = (CPCAP_BIT_ST_DAC_CLK0 | CPCAP_BIT_ST_DAC_CLK1) ; /*19.2Mhz*/ else stdac_freq_config = CPCAP_BIT_ST_DAC_CLK2 ; /* 26Mhz */ /* We need to turn off stdac before changing its settings */ if (previous_state->stdac_mode != CPCAP_AUDIO_STDAC_OFF) { stdac_changes.mask = prev_stdac_data | CPCAP_BIT_DF_RESET_ST_DAC | CPCAP_BIT_ST_CLOCK_TREE_RESET; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_changes.value, stdac_changes.mask); prev_stdac_data = 0; previous_state->stdac_mode = CPCAP_AUDIO_STDAC_OFF; } temp_stdac_rate &= 0x0000000F; temp_stdac_rate = temp_stdac_rate << 4; switch (state->stdac_mode) { case CPCAP_AUDIO_STDAC_ON: stdac_changes.value |= CPCAP_BIT_ST_DAC_EN; /* falling through intentionally */ case CPCAP_AUDIO_STDAC_CLOCK_ONLY: stdac_changes.value |= temp_stdac_rate | CPCAP_BIT_DF_RESET_ST_DAC | stdac_freq_config; sdai_changes.value |= CPCAP_BIT_ST_CLK_EN; break; case CPCAP_AUDIO_STDAC_OFF: default: break; } if (state->rat_type != CPCAP_AUDIO_RAT_NONE) sdai_changes.value |= CPCAP_BIT_ST_DAC_CLK_IN_SEL; /* -True I2S mode -STDAC is Master of Fsync Bclk -STDAC uses DAI1 */ #ifdef AUDIO_I2S_MODE sdai_changes.value |= CPCAP_BIT_DIG_AUD_IN_ST_DAC | CPCAP_BIT_ST_DIG_AUD_FS0 | CPCAP_BIT_ST_DIG_AUD_FS1; #else sdai_changes.value |= CPCAP_BIT_ST_DIG_AUD_FS0 | CPCAP_BIT_DIG_AUD_IN_ST_DAC | CPCAP_BIT_ST_L_TIMESLOT0; #endif /* OK, now start paranoid stdac sequence */ /* TODO: optimize - make less paranoid */ /* FIRST, make sure the frequency config is right... */ logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_freq_config, SDAC_FREQ_MASK); /* Next, write the SDACDI if it's changed */ if (prev_sdai_data != sdai_changes.value) { sdai_changes.mask = sdai_changes.value | prev_sdai_data; prev_sdai_data = sdai_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, sdai_changes.value, sdai_changes.mask); /* Clock tree change -- reset and wait */ stdac_freq_config |= CPCAP_BIT_ST_CLOCK_TREE_RESET; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_freq_config, SDAC_RESET_FREQ_MASK); /* Wait for clock tree reset to complete */ mdelay(CLOCK_TREE_RESET_TIME); } /* Clear old settings */ stdac_changes.mask = stdac_changes.value | prev_stdac_data; prev_stdac_data = stdac_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_changes.value, stdac_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); } }
static void cpcap_audio_configure_stdac(struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { const unsigned int SDAC_FREQ_MASK = CPCAP_BIT_ST_DAC_CLK0 | CPCAP_BIT_ST_DAC_CLK1 | CPCAP_BIT_ST_DAC_CLK2; const unsigned int SDAC_RESET_FREQ_MASK = SDAC_FREQ_MASK | CPCAP_BIT_ST_CLOCK_TREE_RESET; static unsigned int prev_stdac_data, prev_sdai_data; if (is_stdac_changed(state, previous_state)) { unsigned int temp_stdac_rate = state->stdac_rate; struct cpcap_regacc sdai_changes = { 0 }; struct cpcap_regacc stdac_changes = { 0 }; int stdac_freq_config = 0; if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) stdac_freq_config = (CPCAP_BIT_ST_DAC_CLK0 | CPCAP_BIT_ST_DAC_CLK1) ; /*19.2Mhz*/ else stdac_freq_config = CPCAP_BIT_ST_DAC_CLK2 ; /* 26Mhz */ /* We need to turn off stdac before changing its settings */ if (previous_state->stdac_mode != CPCAP_AUDIO_STDAC_OFF) { stdac_changes.mask = prev_stdac_data | CPCAP_BIT_DF_RESET_ST_DAC | CPCAP_BIT_ST_CLOCK_TREE_RESET; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_changes.value, stdac_changes.mask); prev_stdac_data = 0; previous_state->stdac_mode = CPCAP_AUDIO_STDAC_OFF; } temp_stdac_rate &= 0x0000000F; temp_stdac_rate = temp_stdac_rate << 4; switch (state->stdac_mode) { case CPCAP_AUDIO_STDAC_ON: stdac_changes.value |= CPCAP_BIT_ST_DAC_EN; /* falling through intentionally */ case CPCAP_AUDIO_STDAC_CLOCK_ONLY: stdac_changes.value |= temp_stdac_rate | CPCAP_BIT_DF_RESET_ST_DAC | stdac_freq_config; sdai_changes.value |= CPCAP_BIT_ST_CLK_EN; break; case CPCAP_AUDIO_STDAC_OFF: default: break; } if (state->rat_type != CPCAP_AUDIO_RAT_NONE) sdai_changes.value |= CPCAP_BIT_ST_DAC_CLK_IN_SEL; if (state->dai_config == CPCAP_AUDIO_DAI_CONFIG_HIFI_DUPLEX_0) { /* when using DAI0, follow the codec configuration: * 4-slot network, R on slot 0, L on slot 1 */ sdai_changes.value |= CPCAP_BIT_ST_DIG_AUD_FS0 | CPCAP_BIT_ST_L_TIMESLOT0; } else { /* -True I2S mode * -STDAC is Master of Fsync Bclk * -STDAC uses DAI1 */ sdai_changes.value |= CPCAP_BIT_DIG_AUD_IN_ST_DAC | CPCAP_BIT_ST_DIG_AUD_FS0 | CPCAP_BIT_ST_DIG_AUD_FS1; } logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_freq_config, SDAC_FREQ_MASK); /* Next, write the SDACDI if it's changed */ if (prev_sdai_data != sdai_changes.value) { sdai_changes.mask = sdai_changes.value | prev_sdai_data; prev_sdai_data = sdai_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, sdai_changes.value, sdai_changes.mask); /* Clock tree change -- reset and wait */ stdac_freq_config |= CPCAP_BIT_ST_CLOCK_TREE_RESET; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_freq_config, SDAC_RESET_FREQ_MASK); /* Wait for clock tree reset to complete */ mdelay(CLOCK_TREE_RESET_TIME); } /* Clear old settings */ stdac_changes.mask = stdac_changes.value | prev_stdac_data; prev_stdac_data = stdac_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_changes.value, stdac_changes.mask); } }
static void cpcap_audio_configure_output( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { static unsigned int prev_aud_out_data; if (is_output_changed(previous_state, state) || is_codec_changed(previous_state, state) || is_stdac_changed(previous_state, state)) { bool activate_ext_loudspeaker = false; struct cpcap_regacc reg_changes = { 0 }; if (is_output_headset(state) && !is_output_headset(previous_state)) { /* Charge pump should be enabled first * and wait a minimum of 750 uSec * to allow for settling of the negative supply. */ logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, CPCAP_BIT_ST_HS_CP_EN, CPCAP_BIT_ST_HS_CP_EN); /* HS plug-in noise */ /*mdelay(1);*/ mdelay(200); } cpcap_audio_set_output_amp_switches(state); activate_ext_loudspeaker = cpcap_audio_set_bits_for_speaker( state->codec_primary_speaker, state->codec_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->codec_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->stdac_primary_speaker, state->stdac_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->stdac_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->ext_primary_speaker, state->ext_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->ext_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); reg_changes.mask = reg_changes.value | prev_aud_out_data; prev_aud_out_data = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, reg_changes.value, reg_changes.mask); if (!is_output_headset(state) && is_output_headset(previous_state)) { /* When disabling HS output amp, * HS_CP should be turned off after output * amp goes down. */ mdelay(1); logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, 0, CPCAP_BIT_ST_HS_CP_EN); } } }
static void cpcap_audio_set_output_amp_switches(struct cpcap_audio_state *state) { static unsigned int codec_prev_settings = 0, stdac_prev_settings = 0, ext_prev_settings = 0; struct cpcap_regacc reg_changes; unsigned short int value1 = 0, value2 = 0; /* First set codec output amp switches */ value1 = cpcap_audio_get_codec_output_amp_switches(state-> codec_primary_speaker, state->codec_primary_balance); value2 = cpcap_audio_get_codec_output_amp_switches(state-> codec_secondary_speaker, state->codec_primary_balance); reg_changes.mask = value1 | value2 | codec_prev_settings; reg_changes.value = value1 | value2; codec_prev_settings = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, reg_changes.value, reg_changes.mask); /* Second Stdac switches */ value1 = cpcap_audio_get_stdac_output_amp_switches(state-> stdac_primary_speaker, state->stdac_primary_balance); value2 = cpcap_audio_get_stdac_output_amp_switches(state-> stdac_secondary_speaker, state->stdac_primary_balance); reg_changes.mask = value1 | value2 | stdac_prev_settings; reg_changes.value = value1 | value2; if ((state->stdac_primary_speaker == CPCAP_AUDIO_OUT_STEREO_HEADSET && state->stdac_secondary_speaker == CPCAP_AUDIO_OUT_LOUDSPEAKER) || (state->stdac_primary_speaker == CPCAP_AUDIO_OUT_LOUDSPEAKER && state->stdac_secondary_speaker == CPCAP_AUDIO_OUT_STEREO_HEADSET)) reg_changes.value &= ~(CPCAP_BIT_MONO_DAC0 | CPCAP_BIT_MONO_DAC1); stdac_prev_settings = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, reg_changes.value, reg_changes.mask); /* Last External source switches */ value1 = cpcap_audio_get_ext_output_amp_switches(state-> ext_primary_speaker, state->ext_primary_balance); value2 = cpcap_audio_get_ext_output_amp_switches(state-> ext_secondary_speaker, state->ext_primary_balance); reg_changes.mask = value1 | value2 | ext_prev_settings; reg_changes.value = value1 | value2; ext_prev_settings = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, reg_changes.value, reg_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 */ 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 && state->dai_config == CPCAP_AUDIO_DAI_CONFIG_NORMAL) { codec_changes.value |= CPCAP_BIT_CDC_EN_RX; } if (needs_cpcap_mic1(state->microphone)) codec_changes.value |= CPCAP_BIT_MIC1_CDC_EN; if (needs_cpcap_mic2(state->microphone)) codec_changes.value |= CPCAP_BIT_MIC2_CDC_EN; /* use input HPF if either mic is enabled */ if ((codec_changes.value & (CPCAP_BIT_MIC1_CDC_EN | CPCAP_BIT_MIC2_CDC_EN)) != 0) codec_changes.value |= CPCAP_BIT_AUDIHPF_0 | CPCAP_BIT_AUDIHPF_1; if(state->mic_mute == CPCAP_AUDIO_MIC_MUTE) { codec_changes.value &= ~(CPCAP_BIT_MIC1_CDC_EN | CPCAP_BIT_MIC2_CDC_EN); CPCAP_AUDIO_DEBUG_LOG("Mic Muted\n"); } /* 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; /* Bus bus config: Codec is always master*/ cdai_changes.value |= CPCAP_BIT_CDC_DIG_AUD_FS0; /*Codec uses independent PLL in normal operation*/ if (state->dai_config == CPCAP_AUDIO_DAI_CONFIG_NORMAL) cdai_changes.value |= CPCAP_BIT_CDC_PLL_SEL; if (state->rat_type == CPCAP_AUDIO_RAT_CDMA && state->codec_primary_speaker != CPCAP_AUDIO_OUT_BT_MONO) { /* CDMA BP requires I2S mode if not Bluetooth*/ cdai_changes.value |= CPCAP_BIT_CDC_DIG_AUD_FS1 | CPCAP_BIT_CLK_INV; } else if (state->rat_type != CPCAP_AUDIO_RAT_NONE) { /* CDMA BT and all UMTS requires network mode */ cdai_changes.value |= CPCAP_BIT_MIC2_TIMESLOT0; } else { if (state->dai_config == CPCAP_AUDIO_DAI_CONFIG_HIFI_DUPLEX_1) { /* duplex I2S operation on DAI1 (untested) */ cdai_changes.value |= CPCAP_BIT_DIG_AUD_IN | CPCAP_BIT_CDC_DIG_AUD_FS1 | CPCAP_BIT_CLK_INV; } if (needs_outboard_adc(state->microphone)) { /*if we're using the outboard ADC, then it * has slots 0 and 1 so cpcap must be on * 2 and 3. */ cdai_changes.value |= CPCAP_BIT_MIC1_RX_TIMESLOT1 | CPCAP_BIT_MIC2_TIMESLOT0 | CPCAP_BIT_MIC2_TIMESLOT1; } else { if (needs_cpcap_mic2(state->microphone) && !needs_cpcap_mic1(state->microphone)) { /*if we're using *only* cpcap mic2, * put it on slot0 for mono capture. * This requires mic1 be on a slot other * than 0 due to cpcap contention logic. */ cdai_changes.value |= CPCAP_BIT_MIC1_RX_TIMESLOT0; } else { /*otherwise put MIC1 on slot0 and MIC2 * on slot 1 for either MIC1 mono or * MIC1+MIC2 stereo configurations */ cdai_changes.value |= CPCAP_BIT_MIC2_TIMESLOT0; } } } /* 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); } }
void cpcap_audio_init(struct cpcap_audio_state *state) { CPCAP_AUDIO_DEBUG_LOG("%s() called\n", __func__); logged_cpcap_write(state->cpcap, CPCAP_REG_CC, 0, 0xFFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_CDI, 0, 0xBFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, 0, 0xFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, 0, 0x3FFF); logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, 0, 0xFDF); logged_cpcap_write(state->cpcap, CPCAP_REG_TXMP, 0, 0xFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, 0, 0x1FF); /* logged_cpcap_write(state->cpcap, CPCAP_REG_RXVC, 0, 0xFFF); */ logged_cpcap_write(state->cpcap, CPCAP_REG_RXCOA, 0, 0x7FF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXSDOA, 0, 0x1FFF); logged_cpcap_write(state->cpcap, CPCAP_REG_RXEPOA, 0, 0x7FFF); /* Use free running clock for amplifiers */ logged_cpcap_write(state->cpcap, CPCAP_REG_A2LA, CPCAP_BIT_A2_FREE_RUN, CPCAP_BIT_A2_FREE_RUN); audio_reg = regulator_get(NULL, "vaudio"); if (IS_ERR(audio_reg)) CPCAP_AUDIO_ERROR_LOG("could not get regulator for audio\n"); }
static void cpcap_audio_configure_output( struct cpcap_audio_state *state, struct cpcap_audio_state *prev) { static unsigned int prev_aud_out_data; bool activate_ext_loudspeaker = false; struct cpcap_regacc reg_changes = { 0 }; if (!is_output_changed(prev, state) && !is_codec_changed(prev, state) && !is_stdac_changed(prev, state)) return; cpcap_audio_set_output_amp_switches(state); activate_ext_loudspeaker = cpcap_audio_set_bits_for_speaker( state->codec_primary_speaker, state->codec_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->codec_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->stdac_primary_speaker, state->stdac_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->stdac_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->ext_primary_speaker, state->ext_primary_balance, &(reg_changes.value)); activate_ext_loudspeaker = activate_ext_loudspeaker || cpcap_audio_set_bits_for_speaker( state->ext_secondary_speaker, CPCAP_AUDIO_BALANCE_NEUTRAL, &(reg_changes.value)); reg_changes.mask = reg_changes.value | prev_aud_out_data; prev_aud_out_data = reg_changes.value; /* Sleep for 300ms if we are getting into a call to allow the switch to * settle. If we don't do this, it causes a loud pop at the beginning * of the call. */ if (state->rat_type == CPCAP_AUDIO_RAT_CDMA && state->ext_primary_speaker != CPCAP_AUDIO_OUT_NONE && prev->ext_primary_speaker == CPCAP_AUDIO_OUT_NONE) msleep(300); logged_cpcap_write(state->cpcap, CPCAP_REG_RXOA, reg_changes.value, reg_changes.mask); }
static void cpcap_audio_configure_input( struct cpcap_audio_state *state, struct cpcap_audio_state *previous_state) { static unsigned int prev_input_data = 0x0; struct cpcap_regacc reg_changes = { 0 }; if (state->microphone != previous_state->microphone || CODEC_LOOPBACK_CHANGED()) { if (state->codec_mode == CPCAP_AUDIO_CODEC_LOOPBACK) reg_changes.value |= CPCAP_BIT_DLM; #if !defined(CONFIG_MACH_SHOLEST) if (previous_state->microphone == CPCAP_AUDIO_IN_HEADSET) { logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, 0, CPCAP_BIT_GPIO4DRV); } #endif /* !CONFIG_MACH_SHOLEST */ switch (state->microphone) { case CPCAP_AUDIO_IN_HANDSET: reg_changes.value |= CPCAP_BIT_MB_ON1R | CPCAP_BIT_MIC1_MUX | CPCAP_BIT_MIC1_PGA_EN; break; case CPCAP_AUDIO_IN_HEADSET: reg_changes.value |= CPCAP_BIT_HS_MIC_MUX | CPCAP_BIT_MIC1_PGA_EN; #if !defined(CONFIG_MACH_SHOLEST) logged_cpcap_write(state->cpcap, CPCAP_REG_GPIO4, CPCAP_BIT_GPIO4DRV, CPCAP_BIT_GPIO4DRV); #endif /* !CONFIG_MACH_SHOLEST */ break; case CPCAP_AUDIO_IN_EXT_BUS: reg_changes.value |= CPCAP_BIT_EMU_MIC_MUX | CPCAP_BIT_MIC1_PGA_EN; break; case CPCAP_AUDIO_IN_AUX_INTERNAL: reg_changes.value |= CPCAP_BIT_MB_ON1L | CPCAP_BIT_MIC2_MUX | CPCAP_BIT_MIC2_PGA_EN; break; case CPCAP_AUDIO_IN_DUAL_INTERNAL: reg_changes.value |= CPCAP_BIT_MB_ON1R | CPCAP_BIT_MIC1_MUX | CPCAP_BIT_MIC1_PGA_EN | CPCAP_BIT_MB_ON1L | CPCAP_BIT_MIC2_MUX | CPCAP_BIT_MIC2_PGA_EN; break; case CPCAP_AUDIO_IN_DUAL_EXTERNAL: reg_changes.value |= CPCAP_BIT_RX_R_ENCODE | CPCAP_BIT_RX_L_ENCODE; break; case CPCAP_AUDIO_IN_BT_MONO: default: reg_changes.value = 0; break; } reg_changes.mask = reg_changes.value | prev_input_data; prev_input_data = reg_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_TXI, reg_changes.value, reg_changes.mask); } }
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_stdac(struct cpcap_audio_state *state, struct cpcap_audio_state *prev) { const unsigned int SDAC_FREQ_MASK = CPCAP_BIT_ST_DAC_CLK0 | CPCAP_BIT_ST_DAC_CLK1 | CPCAP_BIT_ST_DAC_CLK2; const unsigned int SDAC_RESET_FREQ_MASK = SDAC_FREQ_MASK | CPCAP_BIT_ST_CLOCK_TREE_RESET; static unsigned int prev_stdac_data, prev_sdai_data; if (is_stdac_changed(state, prev)) { unsigned int temp_stdac_rate = state->stdac_rate; struct cpcap_regacc sdai_changes = { 0 }; struct cpcap_regacc stdac_changes = { 0 }; int stdac_freq_config = 0; if (state->rat_type == CPCAP_AUDIO_RAT_CDMA) stdac_freq_config = (CPCAP_BIT_ST_DAC_CLK0 | CPCAP_BIT_ST_DAC_CLK1) ; /*19.2Mhz*/ else stdac_freq_config = CPCAP_BIT_ST_DAC_CLK2 ; /* 26Mhz */ /* We need to turn off stdac before changing its settings */ if (prev->stdac_mode != CPCAP_AUDIO_STDAC_OFF) { stdac_changes.mask = prev_stdac_data | CPCAP_BIT_DF_RESET_ST_DAC | CPCAP_BIT_ST_CLOCK_TREE_RESET; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_changes.value, stdac_changes.mask); prev_stdac_data = 0; prev->stdac_mode = CPCAP_AUDIO_STDAC_OFF; } temp_stdac_rate &= 0x0000000F; temp_stdac_rate = temp_stdac_rate << 4; switch (state->stdac_mode) { case CPCAP_AUDIO_STDAC_ON: stdac_changes.value |= CPCAP_BIT_ST_DAC_EN; /* falling through intentionally */ case CPCAP_AUDIO_STDAC_CLOCK_ONLY: stdac_changes.value |= temp_stdac_rate | CPCAP_BIT_DF_RESET_ST_DAC | stdac_freq_config; sdai_changes.value |= CPCAP_BIT_ST_CLK_EN; break; case CPCAP_AUDIO_STDAC_OFF: default: break; } if (state->rat_type != CPCAP_AUDIO_RAT_NONE) sdai_changes.value |= CPCAP_BIT_ST_DAC_CLK_IN_SEL; /* begin everest change */ /* sdai_changes.value |= CPCAP_BIT_ST_DIG_AUD_FS0 | CPCAP_BIT_DIG_AUD_IN_ST_DAC | CPCAP_BIT_ST_L_TIMESLOT0; */ /* I2S Mode, ignore timeslots, invert bit clock */ sdai_changes.value |= CPCAP_BIT_ST_DIG_AUD_FS0 | CPCAP_BIT_DIG_AUD_IN_ST_DAC | CPCAP_BIT_ST_DIG_AUD_FS1 | CPCAP_BIT_ST_CLK_INV; /* end everest change */ logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_freq_config, SDAC_FREQ_MASK); /* Next, write the SDACDI if it's changed */ if (prev_sdai_data != sdai_changes.value) { sdai_changes.mask = sdai_changes.value | prev_sdai_data; prev_sdai_data = sdai_changes.value; logged_cpcap_write(state->cpcap, CPCAP_REG_SDACDI, sdai_changes.value, sdai_changes.mask); /* Clock tree change -- reset and wait */ stdac_freq_config |= CPCAP_BIT_ST_CLOCK_TREE_RESET; logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_freq_config, SDAC_RESET_FREQ_MASK); /* Wait for clock tree reset to complete */ mdelay(CLOCK_TREE_RESET_DELAY_MS); } /* Clear old settings */ stdac_changes.mask = stdac_changes.value | prev_stdac_data; prev_stdac_data = stdac_changes.value; if ((stdac_changes.value | CPCAP_BIT_ST_DAC_EN) && (state->cpcap->vendor == CPCAP_VENDOR_ST)) { logged_cpcap_write(state->cpcap, CPCAP_REG_TEST, STM_STDAC_EN_TEST_PRE, 0xFFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_ST_TEST1, STM_STDAC_EN_ST_TEST1_PRE, 0xFFFF); } logged_cpcap_write(state->cpcap, CPCAP_REG_SDAC, stdac_changes.value, stdac_changes.mask); if ((stdac_changes.value | CPCAP_BIT_ST_DAC_EN) && (state->cpcap->vendor == CPCAP_VENDOR_ST)) { msleep(STM_STDAC_ACTIVATE_RAMP_TIME); logged_cpcap_write(state->cpcap, CPCAP_REG_ST_TEST1, STM_STDAC_EN_ST_TEST1_POST, 0xFFFF); logged_cpcap_write(state->cpcap, CPCAP_REG_TEST, STM_STDAC_EN_TEST_POST, 0xFFFF); } } }