From ac4e76d0720eeca0dd00ec3bf1fcd80f76d543c0 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Tue, 18 Jun 2013 15:43:43 +0200 Subject: imx233: implement audioin Change-Id: I0cf896f59fd2176217d0dd1f6032c3463b936669 --- firmware/target/arm/imx233/audioin-imx233.c | 158 ++++++++++++++++++++++++++-- firmware/target/arm/imx233/audioin-imx233.h | 16 +++ 2 files changed, 168 insertions(+), 6 deletions(-) diff --git a/firmware/target/arm/imx233/audioin-imx233.c b/firmware/target/arm/imx233/audioin-imx233.c index d3df627037..6c2a212c4d 100644 --- a/firmware/target/arm/imx233/audioin-imx233.c +++ b/firmware/target/arm/imx233/audioin-imx233.c @@ -19,26 +19,172 @@ * ****************************************************************************/ #include "audioin-imx233.h" +#include "pcm_sampr.h" + +/* values in half-dB, one for each setting */ +static int audioin_vol[2][4]; /* 0=left, 1=right */ +static int audioin_select[2]; /* idem */ void imx233_audioin_preinit(void) { /* Enable AUDIOIN block */ imx233_reset_block(&HW_AUDIOIN_CTRL); - /* Enable ADC */ - BF_SET(AUDIOIN_CTRL, CLKGATE); /* Set word-length to 16-bit */ BF_SET(AUDIOIN_CTRL, WORD_LENGTH); + /* Gate Off */ + BF_SET(AUDIOIN_CTRL, CLKGATE); } void imx233_audioin_postinit(void) { } +void imx233_audioin_open(void) +{ + /* Gate On */ + BF_CLR(AUDIOIN_CTRL, CLKGATE); + /* Enable ADC clock */ + BF_CLR(AUDIOIN_ANACLKCTRL, CLKGATE); + /* Power up ADC (WARNING audioout register) */ + BF_CLR(AUDIOOUT_PWRDN, ADC); + /* Start ADC */ + BF_SET(AUDIOIN_CTRL, RUN); +} + void imx233_audioin_close(void) { - /* TODO mute */ - /* Gate off ADC */ - BF_SET(AUDIOIN_ANACLKCTRL, CLKGATE); - /* will also gate off the module */ + /* Stop ADC (doc says it gate off the module but that's not the case) */ BF_CLR(AUDIOIN_CTRL, RUN); + /* Disable ADC clock */ + BF_SET(AUDIOIN_ANACLKCTRL, CLKGATE); + /* Power down ADC (WARNING audioout register) */ + BF_SET(AUDIOOUT_PWRDN, ADC); + /* Gate Off */ + BF_SET(AUDIOIN_CTRL, CLKGATE); +} + +static void apply_config(void) +{ + int select_l = audioin_select[0]; + int select_r = audioin_select[1]; + int vol_l = audioin_vol[0][select_l]; + int vol_r = audioin_vol[1][select_r]; + /* Depending on the input, we have three available volumes to tweak: + * - adc volume: -100dB -> -0.5dB in 0.5dB steps + * - mux gain: 0dB -> 22.5dB in 1.5dB steps + * - mic gain: 0dB -> 40dB in 10dB steps (except for 10) + * + * This means two available volume ranges: + * - line1/line2/hp: -100dB -> 22dB in 0.5dB steps + * - microphone: -100dB -> 62dB in 0.5dB steps + */ + + /* First apply mic gain of possible and necessary + * Only left volume is relevant with microphone + * If gain is > 22dB, use mic gain */ + if(select_l == AUDIOIN_SELECT_MICROPHONE && vol_l > 22 * 2) + { + /* take lowest microphone gain to get back into the -100..22 range + * achievable with mux+adc.*/ + + /* from 52.5 dB and beyond: 40dB gain */ + if(vol_l > 52 * 2) + { + BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 40dB); + vol_l -= 40 * 2; + } + /* from 42.5 dB to 52dB: 30dB gain */ + else if(vol_l > 42 * 2) + { + BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 30dB); + vol_l -= 30 * 2; + } + /* from 22.5 dB to 42dB: 20dB gain */ + else if(vol_l > 22 * 2) + { + BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 20dB); + vol_l -= 20 * 2; + } + /* otherwise 0dB gain */ + else + BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 0dB); + } + /* max is 22dB */ + vol_l = MIN(vol_l, 44); + vol_r = MIN(vol_r, 44); + /* we use the mux volume to reach the volume or higher with 1.5dB steps + * and then we use the ADC to go below 0dB or to obtain 0.5dB accuracy */ + + int mux_vol_l = MAX(0, (vol_l + 2) / 3); /* 1.5dB = 3 * 0.5dB */ + int mux_vol_r = MAX(0, (vol_r + 2) / 3); +#if IMX233_SUBTARGET >= 3700 + unsigned adc_zcd = BM_AUDIOIN_ADCVOL_EN_ADC_ZCD; +#else + unsigned adc_zcd = 0; +#endif + HW_AUDIOIN_ADCVOL = adc_zcd | BF_OR4(AUDIOIN_ADCVOL, SELECT_LEFT(select_l), + SELECT_RIGHT(select_r), GAIN_LEFT(mux_vol_l), GAIN_RIGHT(mux_vol_r)); + + vol_l -= mux_vol_l * 3; /* mux vol is in 1.5dB = 3 * 0.5dB steps */ + vol_r -= mux_vol_l * 3; + vol_l = MIN(MAX(-200, vol_l), -1); + vol_r = MIN(MAX(-200, vol_r), -1); + + /* unmute, enable zero cross and set volume. + * 0xfe is -0.5dB */ + HW_AUDIOIN_ADCVOLUME = BF_OR3(AUDIOIN_ADCVOLUME, EN_ZCD(1), + VOLUME_LEFT(0xff + vol_l), VOLUME_RIGHT(0xff + vol_r)); +} + +void imx233_audioin_select_mux_input(bool right, int select) +{ + audioin_select[right] = select; + apply_config(); +} + +void imx233_audioin_set_vol(bool right, int vol, int select) +{ + audioin_vol[right][select] = vol; + apply_config(); +} + +void imx233_audioin_enable_mic(bool enable) +{ + if(enable) + { + BF_WR_V(AUDIOIN_MICLINE, MIC_RESISTOR, 2KOhm); + BF_WR(AUDIOIN_MICLINE, MIC_BIAS, 4); + BF_WR(AUDIOIN_MICLINE, MIC_SELECT, 1); + } + else + BF_WR_V(AUDIOIN_MICLINE, MIC_RESISTOR, Off); +} + +void imx233_audioin_set_freq(int fsel) +{ + static struct + { + int base_mult; + int src_hold; + int src_int; + int src_frac; + }dacssr[HW_NUM_FREQ] = + { + HW_HAVE_8_([HW_FREQ_8] = { 0x1, 0x3, 0x17, 0xe00 } ,) + HW_HAVE_11_([HW_FREQ_11] = { 0x1, 0x3, 0x11, 0x37 } ,) + HW_HAVE_12_([HW_FREQ_12] = { 0x1, 0x3, 0xf, 0x13ff },) + HW_HAVE_16_([HW_FREQ_16] = { 0x1, 0x1, 0x17, 0xe00},) + HW_HAVE_22_([HW_FREQ_22] = { 0x1, 0x1, 0x11, 0x37 },) + HW_HAVE_24_([HW_FREQ_24] = { 0x1, 0x1, 0xf, 0x13ff },) + HW_HAVE_32_([HW_FREQ_32] = { 0x1, 0x0, 0x17, 0xe00},) + HW_HAVE_44_([HW_FREQ_44] = { 0x1, 0x0, 0x11, 0x37 },) + HW_HAVE_48_([HW_FREQ_48] = { 0x1, 0x0, 0xf, 0x13ff },) + HW_HAVE_64_([HW_FREQ_64] = { 0x2, 0x0, 0x17, 0xe00},) + HW_HAVE_88_([HW_FREQ_88] = { 0x2, 0x0, 0x11, 0x37 },) + HW_HAVE_96_([HW_FREQ_96] = { 0x2, 0x0, 0xf, 0x13ff },) + }; + + HW_AUDIOIN_ADCSRR = BF_OR4(AUDIOIN_ADCSRR, + SRC_FRAC(dacssr[fsel].src_frac), SRC_INT(dacssr[fsel].src_int), + SRC_HOLD(dacssr[fsel].src_hold), BASEMULT(dacssr[fsel].base_mult)); } diff --git a/firmware/target/arm/imx233/audioin-imx233.h b/firmware/target/arm/imx233/audioin-imx233.h index e8c5b36d6d..a36cbf6e1a 100644 --- a/firmware/target/arm/imx233/audioin-imx233.h +++ b/firmware/target/arm/imx233/audioin-imx233.h @@ -26,9 +26,25 @@ #include "system.h" #include "regs/regs-audioin.h" +/* some audioout registers impact audioin */ +#include "regs/regs-audioout.h" + +#define AUDIOIN_SELECT_MICROPHONE 0 +#define AUDIOIN_SELECT_LINE1 1 +#define AUDIOIN_SELECT_HEADPHONE 2 +#define AUDIOIN_SELECT_LINE2 3 void imx233_audioin_preinit(void); void imx233_audioin_postinit(void); +void imx233_audioin_open(void); void imx233_audioin_close(void); +/* use AUDIONIN_SELECT_* values */ +void imx233_audioin_select_mux_input(bool right, int select); +/* volume in half dB */ +void imx233_audioin_set_vol(bool right, int vol, int select); +/* frequency index, NOT the frequency itself */ +void imx233_audioin_set_freq(int fsel); +/* enable microphone */ +void imx233_audioin_enable_mic(bool enable); #endif /* __audioin_imx233__ */ -- cgit v1.2.3