diff options
Diffstat (limited to 'firmware/drivers/audio/wm8758.c')
-rw-r--r-- | firmware/drivers/audio/wm8758.c | 246 |
1 files changed, 103 insertions, 143 deletions
diff --git a/firmware/drivers/audio/wm8758.c b/firmware/drivers/audio/wm8758.c index 7918d03274..d698049a8b 100644 --- a/firmware/drivers/audio/wm8758.c +++ b/firmware/drivers/audio/wm8758.c | |||
@@ -41,117 +41,113 @@ const struct sound_settings_info audiohw_settings[] = { | |||
41 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, | 41 | [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, |
42 | [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, | 42 | [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, |
43 | #ifdef HAVE_RECORDING | 43 | #ifdef HAVE_RECORDING |
44 | [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0}, | 44 | [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 63, 16}, |
45 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0}, | 45 | [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 63, 16}, |
46 | [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16}, | 46 | [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 63, 16}, |
47 | #endif | 47 | #endif |
48 | [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1}, | 48 | [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1}, |
49 | [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1}, | 49 | [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1}, |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* shadow registers */ | 52 | /* shadow registers */ |
53 | unsigned int eq1_reg; | 53 | static unsigned short eq1_reg = EQ1_EQ3DMODE | EQ_GAIN_VALUE(0); |
54 | unsigned int eq5_reg; | 54 | static unsigned short eq5_reg = EQ_GAIN_VALUE(0); |
55 | 55 | ||
56 | /* convert tenth of dB volume (-57..6) to master volume register value */ | 56 | /* convert tenth of dB volume (-57..6) to master volume register value */ |
57 | int tenthdb2master(int db) | 57 | int tenthdb2master(int db) |
58 | { | 58 | { |
59 | /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */ | ||
60 | /* 0111111 == +6dB (0x3f) = 63) */ | ||
61 | /* 0111001 == 0dB (0x39) = 57) */ | ||
62 | /* 0000001 == -56dB (0x01) = */ | ||
63 | /* 0000000 == -57dB (0x00) */ | ||
64 | |||
65 | /* 1000000 == Mute (0x40) */ | ||
66 | |||
67 | if (db < VOLUME_MIN) { | 59 | if (db < VOLUME_MIN) { |
68 | return 0x40; | 60 | return 0x40; |
69 | } else { | 61 | } else { |
70 | return((db/10)+57); | 62 | return (db/10)+57; |
71 | } | 63 | } |
72 | } | 64 | } |
73 | 65 | ||
74 | /* convert tenth of dB volume (-780..0) to mixer volume register value */ | 66 | int sound_val2phys(int setting, int value) |
75 | int tenthdb2mixer(int db) | ||
76 | { | 67 | { |
77 | if (db < -660) /* 1.5 dB steps */ | 68 | int result; |
78 | return (2640 - db) / 15; | ||
79 | else if (db < -600) /* 0.75 dB steps */ | ||
80 | return (990 - db) * 2 / 15; | ||
81 | else if (db < -460) /* 0.5 dB steps */ | ||
82 | return (460 - db) / 5; | ||
83 | else /* 0.25 dB steps */ | ||
84 | return -db * 2 / 5; | ||
85 | } | ||
86 | 69 | ||
87 | #define IPOD_PCM_LEVEL 0x65 /* -6dB */ | 70 | switch(setting) |
71 | { | ||
72 | #ifdef HAVE_RECORDING | ||
73 | case SOUND_LEFT_GAIN: | ||
74 | case SOUND_RIGHT_GAIN: | ||
75 | case SOUND_MIC_GAIN: | ||
76 | result = ((value - 16) * 15) / 2; | ||
77 | break; | ||
78 | #endif | ||
79 | default: | ||
80 | result = value; | ||
81 | break; | ||
82 | } | ||
88 | 83 | ||
89 | //#define BASSCTRL 0x | 84 | return result; |
90 | //#define TREBCTRL 0x0b | 85 | } |
91 | 86 | ||
92 | /* Silently enable / disable audio output */ | 87 | void audiohw_mute(bool mute) |
93 | void audiohw_enable_output(bool enable) | ||
94 | { | 88 | { |
95 | if (enable) | 89 | if (mute) { |
96 | { | 90 | wmcodec_write(DACCTRL, DACCTRL_SOFTMUTE); |
97 | /* reset the I2S controller into known state */ | 91 | } else { |
98 | i2s_reset(); | 92 | wmcodec_write(DACCTRL, 0); |
99 | 93 | } | |
100 | /* TODO: Review the power-up sequence to prevent pops */ | 94 | } |
101 | 95 | ||
102 | wmcodec_write(RESET, 0x1ff); /*Reset*/ | 96 | void audiohw_preinit(void) |
103 | 97 | { | |
104 | wmcodec_write(PWRMGMT1, 0x2b); | 98 | i2s_reset(); |
105 | wmcodec_write(PWRMGMT2, 0x180); | ||
106 | wmcodec_write(PWRMGMT3, 0x6f); | ||
107 | 99 | ||
108 | wmcodec_write(AINTFCE, 0x10); | 100 | wmcodec_write(RESET, RESET_RESET); |
109 | wmcodec_write(CLKCTRL, 0x49); | ||
110 | 101 | ||
111 | wmcodec_write(OUTCTRL, 1); | 102 | wmcodec_write(PWRMGMT1, PWRMGMT1_PLLEN | PWRMGMT1_BIASEN |
103 | | PWRMGMT1_VMIDSEL_5K); | ||
104 | wmcodec_write(PWRMGMT2, PWRMGMT2_ROUT1EN | PWRMGMT2_LOUT1EN); | ||
105 | wmcodec_write(PWRMGMT3, PWRMGMT3_LOUT2EN | PWRMGMT3_ROUT2EN | ||
106 | | PWRMGMT3_RMIXEN | PWRMGMT3_LMIXEN | ||
107 | | PWRMGMT3_DACENR | PWRMGMT3_DACENL); | ||
108 | |||
109 | wmcodec_write(AINTFCE, AINTFCE_IWL_16BIT | AINTFCE_FORMAT_I2S); | ||
110 | wmcodec_write(OUTCTRL, OUTCTRL_VROI); | ||
111 | wmcodec_write(CLKCTRL, CLKCTRL_MS); /* WM8758 is clock master */ | ||
112 | 112 | ||
113 | /* The iPod can handle multiple frequencies, but fix at 44.1KHz | 113 | audiohw_set_sample_rate(WM8758_44100HZ); |
114 | for now */ | ||
115 | audiohw_set_sample_rate(WM8758_44100HZ); | ||
116 | 114 | ||
117 | wmcodec_write(LOUTMIX,0x1); /* Enable mixer */ | 115 | wmcodec_write(LOUTMIX, LOUTMIX_DACL2LMIX); |
118 | wmcodec_write(ROUTMIX,0x1); /* Enable mixer */ | 116 | wmcodec_write(ROUTMIX, ROUTMIX_DACR2RMIX); |
119 | audiohw_mute(0); | 117 | } |
120 | } else { | 118 | |
121 | audiohw_mute(1); | 119 | void audiohw_postinit(void) |
122 | } | 120 | { |
121 | wmcodec_write(PWRMGMT1, PWRMGMT1_PLLEN | PWRMGMT1_BIASEN | ||
122 | | PWRMGMT1_VMIDSEL_75K); | ||
123 | /* lower the VMID power consumption */ | ||
124 | audiohw_mute(false); | ||
123 | } | 125 | } |
124 | 126 | ||
125 | void audiohw_set_master_vol(int vol_l, int vol_r) | 127 | void audiohw_set_master_vol(int vol_l, int vol_r) |
126 | { | 128 | { |
127 | /* OUT1 */ | 129 | /* OUT1 */ |
128 | wmcodec_write(LOUT1VOL, 0x080 | vol_l); | 130 | wmcodec_write(LOUT1VOL, LOUT1VOL_LOUT1ZC | vol_l); |
129 | wmcodec_write(ROUT1VOL, 0x180 | vol_r); | 131 | wmcodec_write(ROUT1VOL, ROUT1VOL_OUT1VU | ROUT1VOL_ROUT1ZC | vol_r); |
130 | } | 132 | } |
131 | 133 | ||
132 | void audiohw_set_lineout_vol(int vol_l, int vol_r) | 134 | void audiohw_set_lineout_vol(int vol_l, int vol_r) |
133 | { | 135 | { |
134 | /* OUT2 */ | 136 | /* OUT2 */ |
135 | wmcodec_write(LOUT2VOL, vol_l); | 137 | wmcodec_write(LOUT2VOL, LOUT2VOL_LOUT2ZC | vol_l); |
136 | wmcodec_write(ROUT2VOL, 0x100 | vol_r); | 138 | wmcodec_write(ROUT2VOL, ROUT2VOL_OUT2VU | ROUT2VOL_ROUT2ZC | vol_r); |
137 | } | ||
138 | |||
139 | void audiohw_set_mixer_vol(int channel1, int channel2) | ||
140 | { | ||
141 | (void)channel1; | ||
142 | (void)channel2; | ||
143 | } | 139 | } |
144 | 140 | ||
145 | void audiohw_set_bass(int value) | 141 | void audiohw_set_bass(int value) |
146 | { | 142 | { |
147 | eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value); | 143 | eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value); |
148 | wmcodec_write(EQ1, 0x100 | eq1_reg); | 144 | wmcodec_write(EQ1, eq1_reg); |
149 | } | 145 | } |
150 | 146 | ||
151 | void audiohw_set_bass_cutoff(int value) | 147 | void audiohw_set_bass_cutoff(int value) |
152 | { | 148 | { |
153 | eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value); | 149 | eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value); |
154 | wmcodec_write(EQ1, 0x100 | eq1_reg); | 150 | wmcodec_write(EQ1, eq1_reg); |
155 | } | 151 | } |
156 | 152 | ||
157 | void audiohw_set_treble(int value) | 153 | void audiohw_set_treble(int value) |
@@ -166,31 +162,16 @@ void audiohw_set_treble_cutoff(int value) | |||
166 | wmcodec_write(EQ5, eq5_reg); | 162 | wmcodec_write(EQ5, eq5_reg); |
167 | } | 163 | } |
168 | 164 | ||
169 | void audiohw_mute(bool mute) | ||
170 | { | ||
171 | if (mute) | ||
172 | { | ||
173 | /* Set DACMU = 1 to soft-mute the audio DACs. */ | ||
174 | wmcodec_write(DACCTRL, 0x40); | ||
175 | } else { | ||
176 | /* Set DACMU = 0 to soft-un-mute the audio DACs. */ | ||
177 | wmcodec_write(DACCTRL, 0x0); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | /* Nice shutdown of WM8758 codec */ | 165 | /* Nice shutdown of WM8758 codec */ |
182 | void audiohw_close(void) | 166 | void audiohw_close(void) |
183 | { | 167 | { |
184 | audiohw_mute(1); | 168 | audiohw_mute(true); |
185 | |||
186 | wmcodec_write(PWRMGMT3, 0x0); | ||
187 | |||
188 | wmcodec_write(PWRMGMT1, 0x0); | ||
189 | 169 | ||
190 | wmcodec_write(PWRMGMT2, 0x40); | 170 | wmcodec_write(PWRMGMT3, 0); |
171 | wmcodec_write(PWRMGMT1, 0); | ||
172 | wmcodec_write(PWRMGMT2, PWRMGMT2_SLEEP); | ||
191 | } | 173 | } |
192 | 174 | ||
193 | /* Change the order of the noise shaper, 5th order is recommended above 32kHz */ | ||
194 | void audiohw_set_nsorder(int order) | 175 | void audiohw_set_nsorder(int order) |
195 | { | 176 | { |
196 | (void)order; | 177 | (void)order; |
@@ -202,89 +183,68 @@ void audiohw_set_sample_rate(int sampling_control) | |||
202 | /**** We force 44.1KHz for now. ****/ | 183 | /**** We force 44.1KHz for now. ****/ |
203 | (void)sampling_control; | 184 | (void)sampling_control; |
204 | 185 | ||
205 | /* set clock div */ | ||
206 | wmcodec_write(CLKCTRL, 1 | (0 << 2) | (2 << 5)); | ||
207 | |||
208 | /* setup PLL for MHZ=11.2896 */ | 186 | /* setup PLL for MHZ=11.2896 */ |
209 | wmcodec_write(PLLN, (1 << 4) | 0x7); | 187 | wmcodec_write(PLLN, PLLN_PLLPRESCALE | 0x7); |
210 | wmcodec_write(PLLK1, 0x21); | 188 | wmcodec_write(PLLK1, 0x21); |
211 | wmcodec_write(PLLK2, 0x161); | 189 | wmcodec_write(PLLK2, 0x161); |
212 | wmcodec_write(PLLK3, 0x26); | 190 | wmcodec_write(PLLK3, 0x26); |
213 | 191 | ||
214 | /* set clock div */ | 192 | /* set clock div */ |
215 | wmcodec_write(CLKCTRL, 1 | (1 << 2) | (2 << 5) | (1 << 8)); | 193 | wmcodec_write(CLKCTRL, CLKCTRL_CLKSEL | CLKCTRL_MCLKDIV_2 |
194 | | CLKCTRL_BCLKDIV_2 | CLKCTRL_MS); | ||
216 | 195 | ||
217 | /* set srate */ | 196 | wmcodec_write(ADDCTRL, ADDCTRL_SR_48kHz | ADDCTRL_SLOWCLKEN); |
218 | wmcodec_write(SRATECTRL, (0 << 1)); | 197 | /* SLOWCLK enabled for zero cross timeout to work */ |
219 | } | 198 | } |
220 | 199 | ||
221 | void audiohw_enable_recording(bool source_mic) | 200 | void audiohw_enable_recording(bool source_mic) |
222 | { | 201 | { |
223 | (void)source_mic; /* We only have a line-in (I think) */ | 202 | (void)source_mic; /* We only have a line-in (I think) */ |
224 | |||
225 | /* reset the I2S controller into known state */ | ||
226 | i2s_reset(); | ||
227 | |||
228 | wmcodec_write(RESET, 0x1ff); /*Reset*/ | ||
229 | 203 | ||
230 | wmcodec_write(PWRMGMT1, 0x2b); | 204 | wmcodec_write(PWRMGMT2, PWRMGMT2_ROUT1EN | PWRMGMT2_LOUT1EN |
231 | wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */ | 205 | | PWRMGMT2_INPGAENR | PWRMGMT2_INPGAENL |
232 | wmcodec_write(PWRMGMT3, 0x6f); | 206 | | PWRMGMT2_ADCENR | PWRMGMT2_ADCENL); |
233 | 207 | ||
234 | wmcodec_write(AINTFCE, 0x10); | 208 | wmcodec_write(INCTRL, INCTRL_R2_2INPGA | INCTRL_L2_2INPGA); |
235 | wmcodec_write(CLKCTRL, 0x49); | ||
236 | 209 | ||
237 | wmcodec_write(OUTCTRL, 1); | 210 | wmcodec_write(LADCBOOST, LADCBOOST_L2_2BOOST(5)); |
238 | 211 | wmcodec_write(RADCBOOST, RADCBOOST_R2_2BOOST(5)); | |
239 | /* The iPod can handle multiple frequencies, but fix at 44.1KHz | ||
240 | for now */ | ||
241 | audiohw_set_sample_rate(WM8758_44100HZ); | ||
242 | |||
243 | wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */ | ||
244 | |||
245 | /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */ | ||
246 | /* 000 = disabled | ||
247 | 001 = -12dB | ||
248 | 010 = -9dB | ||
249 | 011 = -6dB | ||
250 | 100 = -3dB | ||
251 | 101 = 0dB | ||
252 | 110 = 3dB | ||
253 | 111 = 6dB | ||
254 | */ | ||
255 | wmcodec_write(LADCBOOST,0x50); | ||
256 | wmcodec_write(RADCBOOST,0x50); | ||
257 | |||
258 | /* Set L/R input PGA Volume to 0db */ | ||
259 | // wm8758_write(LINPGAVOL,0x3f); | ||
260 | // wm8758_write(RINPGAVOL,0x13f); | ||
261 | 212 | ||
262 | /* Enable monitoring */ | 213 | /* Enable monitoring */ |
263 | wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/ | 214 | wmcodec_write(LOUTMIX, LOUTMIX_BYP2LMIXVOL(5) |
264 | wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/ | 215 | | LOUTMIX_BYPL2LMIX | LOUTMIX_DACL2LMIX); |
265 | 216 | wmcodec_write(ROUTMIX, ROUTMIX_BYP2RMIXVOL(5) | |
266 | audiohw_mute(0); | 217 | | ROUTMIX_BYPR2RMIX | ROUTMIX_DACR2RMIX); |
267 | } | 218 | } |
268 | 219 | ||
269 | void audiohw_disable_recording(void) { | 220 | void audiohw_disable_recording(void) |
270 | audiohw_mute(1); | 221 | { |
271 | 222 | wmcodec_write(LOUTMIX, LOUTMIX_DACL2LMIX); | |
272 | wmcodec_write(PWRMGMT3, 0x0); | 223 | wmcodec_write(ROUTMIX, ROUTMIX_DACR2RMIX); |
273 | 224 | ||
274 | wmcodec_write(PWRMGMT1, 0x0); | 225 | wmcodec_write(PWRMGMT2, PWRMGMT2_ROUT1EN | PWRMGMT2_LOUT1EN); |
275 | |||
276 | wmcodec_write(PWRMGMT2, 0x40); | ||
277 | } | 226 | } |
278 | 227 | ||
279 | void audiohw_set_recvol(int left, int right, int type) { | 228 | void audiohw_set_recvol(int left, int right, int type) |
280 | 229 | { | |
281 | (void)left; | 230 | switch (type) |
282 | (void)right; | 231 | { |
283 | (void)type; | 232 | case AUDIO_GAIN_MIC: |
233 | right = left; | ||
234 | /* fall through */ | ||
235 | case AUDIO_GAIN_LINEIN: | ||
236 | wmcodec_write(LINPGAVOL, LINPGAVOL_INPGAZCL | ||
237 | | (left & LINPGAVOL_INPGAVOL_MASK)); | ||
238 | wmcodec_write(RINPGAVOL, RINPGAVOL_INPGAVU | RINPGAVOL_INPGAZCR | ||
239 | | (right & RINPGAVOL_INPGAVOL_MASK)); | ||
240 | break; | ||
241 | default: | ||
242 | return; | ||
243 | } | ||
284 | } | 244 | } |
285 | 245 | ||
286 | void audiohw_set_monitor(bool enable) { | 246 | void audiohw_set_monitor(bool enable) |
287 | 247 | { | |
288 | (void)enable; | 248 | (void)enable; |
289 | } | 249 | } |
290 | 250 | ||