diff options
Diffstat (limited to 'firmware/target/arm/imx233/audioin-imx233.c')
-rw-r--r-- | firmware/target/arm/imx233/audioin-imx233.c | 158 |
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 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "audioin-imx233.h" | 21 | #include "audioin-imx233.h" |
22 | #include "pcm_sampr.h" | ||
23 | |||
24 | /* values in half-dB, one for each setting */ | ||
25 | static int audioin_vol[2][4]; /* 0=left, 1=right */ | ||
26 | static int audioin_select[2]; /* idem */ | ||
22 | 27 | ||
23 | void imx233_audioin_preinit(void) | 28 | void imx233_audioin_preinit(void) |
24 | { | 29 | { |
25 | /* Enable AUDIOIN block */ | 30 | /* Enable AUDIOIN block */ |
26 | imx233_reset_block(&HW_AUDIOIN_CTRL); | 31 | imx233_reset_block(&HW_AUDIOIN_CTRL); |
27 | /* Enable ADC */ | ||
28 | BF_SET(AUDIOIN_CTRL, CLKGATE); | ||
29 | /* Set word-length to 16-bit */ | 32 | /* Set word-length to 16-bit */ |
30 | BF_SET(AUDIOIN_CTRL, WORD_LENGTH); | 33 | BF_SET(AUDIOIN_CTRL, WORD_LENGTH); |
34 | /* Gate Off */ | ||
35 | BF_SET(AUDIOIN_CTRL, CLKGATE); | ||
31 | } | 36 | } |
32 | 37 | ||
33 | void imx233_audioin_postinit(void) | 38 | void imx233_audioin_postinit(void) |
34 | { | 39 | { |
35 | } | 40 | } |
36 | 41 | ||
42 | void imx233_audioin_open(void) | ||
43 | { | ||
44 | /* Gate On */ | ||
45 | BF_CLR(AUDIOIN_CTRL, CLKGATE); | ||
46 | /* Enable ADC clock */ | ||
47 | BF_CLR(AUDIOIN_ANACLKCTRL, CLKGATE); | ||
48 | /* Power up ADC (WARNING audioout register) */ | ||
49 | BF_CLR(AUDIOOUT_PWRDN, ADC); | ||
50 | /* Start ADC */ | ||
51 | BF_SET(AUDIOIN_CTRL, RUN); | ||
52 | } | ||
53 | |||
37 | void imx233_audioin_close(void) | 54 | void imx233_audioin_close(void) |
38 | { | 55 | { |
39 | /* TODO mute */ | 56 | /* Stop ADC (doc says it gate off the module but that's not the case) */ |
40 | /* Gate off ADC */ | ||
41 | BF_SET(AUDIOIN_ANACLKCTRL, CLKGATE); | ||
42 | /* will also gate off the module */ | ||
43 | BF_CLR(AUDIOIN_CTRL, RUN); | 57 | BF_CLR(AUDIOIN_CTRL, RUN); |
58 | /* Disable ADC clock */ | ||
59 | BF_SET(AUDIOIN_ANACLKCTRL, CLKGATE); | ||
60 | /* Power down ADC (WARNING audioout register) */ | ||
61 | BF_SET(AUDIOOUT_PWRDN, ADC); | ||
62 | /* Gate Off */ | ||
63 | BF_SET(AUDIOIN_CTRL, CLKGATE); | ||
64 | } | ||
65 | |||
66 | static void apply_config(void) | ||
67 | { | ||
68 | int select_l = audioin_select[0]; | ||
69 | int select_r = audioin_select[1]; | ||
70 | int vol_l = audioin_vol[0][select_l]; | ||
71 | int vol_r = audioin_vol[1][select_r]; | ||
72 | /* Depending on the input, we have three available volumes to tweak: | ||
73 | * - adc volume: -100dB -> -0.5dB in 0.5dB steps | ||
74 | * - mux gain: 0dB -> 22.5dB in 1.5dB steps | ||
75 | * - mic gain: 0dB -> 40dB in 10dB steps (except for 10) | ||
76 | * | ||
77 | * This means two available volume ranges: | ||
78 | * - line1/line2/hp: -100dB -> 22dB in 0.5dB steps | ||
79 | * - microphone: -100dB -> 62dB in 0.5dB steps | ||
80 | */ | ||
81 | |||
82 | /* First apply mic gain of possible and necessary | ||
83 | * Only left volume is relevant with microphone | ||
84 | * If gain is > 22dB, use mic gain */ | ||
85 | if(select_l == AUDIOIN_SELECT_MICROPHONE && vol_l > 22 * 2) | ||
86 | { | ||
87 | /* take lowest microphone gain to get back into the -100..22 range | ||
88 | * achievable with mux+adc.*/ | ||
89 | |||
90 | /* from 52.5 dB and beyond: 40dB gain */ | ||
91 | if(vol_l > 52 * 2) | ||
92 | { | ||
93 | BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 40dB); | ||
94 | vol_l -= 40 * 2; | ||
95 | } | ||
96 | /* from 42.5 dB to 52dB: 30dB gain */ | ||
97 | else if(vol_l > 42 * 2) | ||
98 | { | ||
99 | BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 30dB); | ||
100 | vol_l -= 30 * 2; | ||
101 | } | ||
102 | /* from 22.5 dB to 42dB: 20dB gain */ | ||
103 | else if(vol_l > 22 * 2) | ||
104 | { | ||
105 | BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 20dB); | ||
106 | vol_l -= 20 * 2; | ||
107 | } | ||
108 | /* otherwise 0dB gain */ | ||
109 | else | ||
110 | BF_WR_V(AUDIOIN_MICLINE, MIC_GAIN, 0dB); | ||
111 | } | ||
112 | /* max is 22dB */ | ||
113 | vol_l = MIN(vol_l, 44); | ||
114 | vol_r = MIN(vol_r, 44); | ||
115 | /* we use the mux volume to reach the volume or higher with 1.5dB steps | ||
116 | * and then we use the ADC to go below 0dB or to obtain 0.5dB accuracy */ | ||
117 | |||
118 | int mux_vol_l = MAX(0, (vol_l + 2) / 3); /* 1.5dB = 3 * 0.5dB */ | ||
119 | int mux_vol_r = MAX(0, (vol_r + 2) / 3); | ||
120 | #if IMX233_SUBTARGET >= 3700 | ||
121 | unsigned adc_zcd = BM_AUDIOIN_ADCVOL_EN_ADC_ZCD; | ||
122 | #else | ||
123 | unsigned adc_zcd = 0; | ||
124 | #endif | ||
125 | HW_AUDIOIN_ADCVOL = adc_zcd | BF_OR4(AUDIOIN_ADCVOL, SELECT_LEFT(select_l), | ||
126 | SELECT_RIGHT(select_r), GAIN_LEFT(mux_vol_l), GAIN_RIGHT(mux_vol_r)); | ||
127 | |||
128 | vol_l -= mux_vol_l * 3; /* mux vol is in 1.5dB = 3 * 0.5dB steps */ | ||
129 | vol_r -= mux_vol_l * 3; | ||
130 | vol_l = MIN(MAX(-200, vol_l), -1); | ||
131 | vol_r = MIN(MAX(-200, vol_r), -1); | ||
132 | |||
133 | /* unmute, enable zero cross and set volume. | ||
134 | * 0xfe is -0.5dB */ | ||
135 | HW_AUDIOIN_ADCVOLUME = BF_OR3(AUDIOIN_ADCVOLUME, EN_ZCD(1), | ||
136 | VOLUME_LEFT(0xff + vol_l), VOLUME_RIGHT(0xff + vol_r)); | ||
137 | } | ||
138 | |||
139 | void imx233_audioin_select_mux_input(bool right, int select) | ||
140 | { | ||
141 | audioin_select[right] = select; | ||
142 | apply_config(); | ||
143 | } | ||
144 | |||
145 | void imx233_audioin_set_vol(bool right, int vol, int select) | ||
146 | { | ||
147 | audioin_vol[right][select] = vol; | ||
148 | apply_config(); | ||
149 | } | ||
150 | |||
151 | void imx233_audioin_enable_mic(bool enable) | ||
152 | { | ||
153 | if(enable) | ||
154 | { | ||
155 | BF_WR_V(AUDIOIN_MICLINE, MIC_RESISTOR, 2KOhm); | ||
156 | BF_WR(AUDIOIN_MICLINE, MIC_BIAS, 4); | ||
157 | BF_WR(AUDIOIN_MICLINE, MIC_SELECT, 1); | ||
158 | } | ||
159 | else | ||
160 | BF_WR_V(AUDIOIN_MICLINE, MIC_RESISTOR, Off); | ||
161 | } | ||
162 | |||
163 | void imx233_audioin_set_freq(int fsel) | ||
164 | { | ||
165 | static struct | ||
166 | { | ||
167 | int base_mult; | ||
168 | int src_hold; | ||
169 | int src_int; | ||
170 | int src_frac; | ||
171 | }dacssr[HW_NUM_FREQ] = | ||
172 | { | ||
173 | HW_HAVE_8_([HW_FREQ_8] = { 0x1, 0x3, 0x17, 0xe00 } ,) | ||
174 | HW_HAVE_11_([HW_FREQ_11] = { 0x1, 0x3, 0x11, 0x37 } ,) | ||
175 | HW_HAVE_12_([HW_FREQ_12] = { 0x1, 0x3, 0xf, 0x13ff },) | ||
176 | HW_HAVE_16_([HW_FREQ_16] = { 0x1, 0x1, 0x17, 0xe00},) | ||
177 | HW_HAVE_22_([HW_FREQ_22] = { 0x1, 0x1, 0x11, 0x37 },) | ||
178 | HW_HAVE_24_([HW_FREQ_24] = { 0x1, 0x1, 0xf, 0x13ff },) | ||
179 | HW_HAVE_32_([HW_FREQ_32] = { 0x1, 0x0, 0x17, 0xe00},) | ||
180 | HW_HAVE_44_([HW_FREQ_44] = { 0x1, 0x0, 0x11, 0x37 },) | ||
181 | HW_HAVE_48_([HW_FREQ_48] = { 0x1, 0x0, 0xf, 0x13ff },) | ||
182 | HW_HAVE_64_([HW_FREQ_64] = { 0x2, 0x0, 0x17, 0xe00},) | ||
183 | HW_HAVE_88_([HW_FREQ_88] = { 0x2, 0x0, 0x11, 0x37 },) | ||
184 | HW_HAVE_96_([HW_FREQ_96] = { 0x2, 0x0, 0xf, 0x13ff },) | ||
185 | }; | ||
186 | |||
187 | HW_AUDIOIN_ADCSRR = BF_OR4(AUDIOIN_ADCSRR, | ||
188 | SRC_FRAC(dacssr[fsel].src_frac), SRC_INT(dacssr[fsel].src_int), | ||
189 | SRC_HOLD(dacssr[fsel].src_hold), BASEMULT(dacssr[fsel].base_mult)); | ||
44 | } | 190 | } |