summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm/imx233/audioin-imx233.c
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-06-18 15:43:43 +0200
committerAmaury Pouly <amaury.pouly@gmail.com>2013-06-18 15:43:43 +0200
commitac4e76d0720eeca0dd00ec3bf1fcd80f76d543c0 (patch)
tree44ecd9aac360a15043e62ca2e49a58525fd040c1 /firmware/target/arm/imx233/audioin-imx233.c
parent57bb7b2d2704166b5d4dd307d3ae8d8ae99afbbd (diff)
downloadrockbox-ac4e76d0720eeca0dd00ec3bf1fcd80f76d543c0.tar.gz
rockbox-ac4e76d0720eeca0dd00ec3bf1fcd80f76d543c0.tar.bz2
rockbox-ac4e76d0720eeca0dd00ec3bf1fcd80f76d543c0.zip
imx233: implement audioin
Change-Id: I0cf896f59fd2176217d0dd1f6032c3463b936669
Diffstat (limited to 'firmware/target/arm/imx233/audioin-imx233.c')
-rw-r--r--firmware/target/arm/imx233/audioin-imx233.c158
1 files changed, 152 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));
}