summaryrefslogtreecommitdiff
path: root/firmware/drivers/audio/wm8731.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/audio/wm8731.c')
-rw-r--r--firmware/drivers/audio/wm8731.c194
1 files changed, 103 insertions, 91 deletions
diff --git a/firmware/drivers/audio/wm8731.c b/firmware/drivers/audio/wm8731.c
index 2f882e8fe1..3cfd3e4b92 100644
--- a/firmware/drivers/audio/wm8731.c
+++ b/firmware/drivers/audio/wm8731.c
@@ -7,7 +7,7 @@
7 * \/ \/ \/ \/ \/ 7 * \/ \/ \/ \/ \/
8 * $Id$ 8 * $Id$
9 * 9 *
10 * Driver for WM8731L audio codec 10 * Driver for WM8711/WM8721/WM8731 audio codecs
11 * 11 *
12 * Based on code from the ipodlinux project - http://ipodlinux.org/ 12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in January 2006 13 * Adapted for Rockbox in January 2006
@@ -43,7 +43,7 @@ const struct sound_settings_info audiohw_settings[] = {
43 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0}, 43 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
44 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, 44 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
45 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, 45 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
46#ifdef HAVE_RECORDING 46#if defined(HAVE_WM8731) && defined(HAVE_RECORDING)
47 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23}, 47 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 31, 23},
48 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23}, 48 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 31, 23},
49 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 0}, 49 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 1, 0},
@@ -53,42 +53,57 @@ const struct sound_settings_info audiohw_settings[] = {
53/* Init values/shadows 53/* Init values/shadows
54 * Ignore bit 8 since that only specifies "both" for updating 54 * Ignore bit 8 since that only specifies "both" for updating
55 * gains - "RESET" (15h) not included */ 55 * gains - "RESET" (15h) not included */
56static unsigned char wm8731_regs[WM8731_NUM_REGS] = 56static unsigned char wmc_regs[WMC_NUM_REGS] =
57{ 57{
58 [LINVOL] = 0x97, 58#ifdef HAVE_WM8731
59 [RINVOL] = 0x97, 59 [LINVOL] = LINVOL_DEFAULT,
60 [LOUTVOL] = 0x79 | ROUTVOL_RZCEN, 60 [RINVOL] = RINVOL_DEFAULT,
61 [ROUTVOL] = 0x79 | ROUTVOL_RZCEN, 61#endif
62 [AAPCTRL] = 0x0a, 62 [LOUTVOL] = LOUTVOL_DEFAULT | WMC_OUT_ZCEN,
63 [DAPCTRL] = 0x08, 63 [ROUTVOL] = LOUTVOL_DEFAULT | WMC_OUT_ZCEN,
64 [PDCTRL] = 0x9f, 64#if defined(HAVE_WM8711) || defined(HAVE_WM8731)
65 [AINTFCE] = 0x0a, 65 /* BYPASS on by default - OFF until needed */
66 [SAMPCTRL] = 0x00, 66 [AAPCTRL] = AAPCTRL_DEFAULT & ~AAPCTRL_BYPASS,
67 [ACTIVECTRL] = 0x00, 67 /* CLKOUT and OSC on by default - OFF unless needed by a target */
68 [PDCTRL] = PDCTRL_DEFAULT | PDCTRL_CLKOUTPD | PDCTRL_OSCPD,
69#elif defined(HAVE_WM8721)
70 /* No BYPASS */
71 [AAPCTRL] = AAPCTRL_DEFAULT,
72 /* No CLKOUT or OSC */
73 [PDCTRL] = PDCTRL_DEFAULT,
74#endif
75 [DAPCTRL] = DAPCTRL_DEFAULT,
76#ifndef CODEC_SLAVE
77 [AINTFCE] = AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT | AINTFCE_MS,
78#else
79 [AINTFCE] = AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT,
80#endif
81 [SAMPCTRL] = SAMPCTRL_DEFAULT,
82 [ACTIVECTRL] = ACTIVECTRL_DEFAULT,
68}; 83};
69 84
70static void wm8731_write(int reg, unsigned val) 85static void wmc_write(int reg, unsigned val)
71{ 86{
72 if ((unsigned)reg >= WM8731_NUM_REGS) 87 if ((unsigned)reg >= WMC_NUM_REGS)
73 return; 88 return;
74 89
75 wm8731_regs[reg] = (unsigned char)val; 90 wmc_regs[reg] = (unsigned char)val;
76 wmcodec_write(reg, val); 91 wmcodec_write(reg, val);
77} 92}
78 93
79static void wm8731_set(int reg, unsigned bits) 94static void wmc_set(int reg, unsigned bits)
80{ 95{
81 wm8731_write(reg, wm8731_regs[reg] | bits); 96 wmc_write(reg, wmc_regs[reg] | bits);
82} 97}
83 98
84static void wm8731_clear(int reg, unsigned bits) 99static void wmc_clear(int reg, unsigned bits)
85{ 100{
86 wm8731_write(reg, wm8731_regs[reg] & ~bits); 101 wmc_write(reg, wmc_regs[reg] & ~bits);
87} 102}
88 103
89static void wm8731_write_masked(int reg, unsigned bits, unsigned mask) 104static void wmc_write_masked(int reg, unsigned bits, unsigned mask)
90{ 105{
91 wm8731_write(reg, (wm8731_regs[reg] & ~mask) | (bits & mask)); 106 wmc_write(reg, (wmc_regs[reg] & ~mask) | (bits & mask));
92} 107}
93 108
94/* convert tenth of dB volume (-730..60) to master volume register value */ 109/* convert tenth of dB volume (-730..60) to master volume register value */
@@ -134,54 +149,50 @@ void audiohw_mute(bool mute)
134{ 149{
135 if (mute) { 150 if (mute) {
136 /* Set DACMU = 1 to soft-mute the audio DACs. */ 151 /* Set DACMU = 1 to soft-mute the audio DACs. */
137 wm8731_set(DAPCTRL, DAPCTRL_DACMU); 152 wmc_set(DAPCTRL, DAPCTRL_DACMU);
138 } else { 153 } else {
139 /* Set DACMU = 0 to soft-un-mute the audio DACs. */ 154 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
140 wm8731_clear(DAPCTRL, DAPCTRL_DACMU); 155 wmc_clear(DAPCTRL, DAPCTRL_DACMU);
141 } 156 }
142} 157}
143 158
144static void codec_set_active(int active) 159static void codec_set_active(int active)
145{ 160{
146 /* set active to 0x0 or 0x1 */ 161 /* set active to 0x0 or 0x1 */
147 wm8731_write(ACTIVECTRL, active ? ACTIVECTRL_ACTIVE : 0); 162 wmc_write(ACTIVECTRL, active ? ACTIVECTRL_ACTIVE : 0);
148} 163}
149 164
150void audiohw_preinit(void) 165void audiohw_preinit(void)
151{ 166{
152 /* POWER UP SEQUENCE */ 167 /* POWER UP SEQUENCE */
153 /* 1) Switch on power supplies. By default the WM8731 is in Standby Mode, 168 /* 1) Switch on power supplies. By default the WM codec is in Standby Mode,
154 * the DAC is digitally muted and the Audio Interface and Outputs are 169 * the DAC is digitally muted and the Audio Interface and Outputs are
155 * all OFF. */ 170 * all OFF. */
156 wmcodec_write(RESET, RESET_RESET); 171 wmcodec_write(RESET, RESET_RESET);
157 172
158 /* 2) Set all required bits in the Power Down register (0Ch) to '0'; 173 /* 2) Set all required bits in the Power Down register (0Ch) to '0';
159 * EXCEPT the OUTPD bit, this should be set to '1' (Default). */ 174 * EXCEPT the OUTPD bit, this should be set to '1' (Default). */
160 wm8731_clear(PDCTRL, PDCTRL_DACPD | PDCTRL_POWEROFF); 175 wmc_clear(PDCTRL, PDCTRL_DACPD | PDCTRL_POWEROFF);
161 176
162 /* 3) Set required values in all other registers except 12h (Active). */ 177 /* 3) Set required values in all other registers except 12h (Active). */
163 wm8731_write(AINTFCE, 178 wmc_set(AINTFCE, 0); /* Set no bits - write init/shadow value */
164#ifndef CODEC_SLAVE
165 AINTFCE_MS |
166#endif
167 AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT);
168 179
169 wm8731_set(AAPCTRL, AAPCTRL_DACSEL); 180 wmc_set(AAPCTRL, AAPCTRL_DACSEL);
170 wm8731_write(SAMPCTRL, WM8731_USB24_44100HZ); 181 wmc_write(SAMPCTRL, WMC_USB24_44100HZ);
182
183 /* 4) Set the 'Active' bit in register 12h. */
184 codec_set_active(true);
171 185
172 /* 5) The last write of the sequence should be setting OUTPD to '0' 186 /* 5) The last write of the sequence should be setting OUTPD to '0'
173 * (active) in register 0Ch, enabling the DAC signal path, free 187 * (active) in register 0Ch, enabling the DAC signal path, free
174 * of any significant power-up noise. */ 188 * of any significant power-up noise. */
175 wm8731_clear(PDCTRL, PDCTRL_OUTPD); 189 wmc_clear(PDCTRL, PDCTRL_OUTPD);
176} 190}
177 191
178void audiohw_postinit(void) 192void audiohw_postinit(void)
179{ 193{
180 sleep(HZ); 194 sleep(HZ);
181 195
182 /* 4) Set the 'Active' bit in register 12h. */
183 codec_set_active(true);
184
185 audiohw_mute(false); 196 audiohw_mute(false);
186 197
187#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) 198#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
@@ -197,51 +208,53 @@ void audiohw_set_master_vol(int vol_l, int vol_r)
197 /* 1111001 == 0dB */ 208 /* 1111001 == 0dB */
198 /* 0110000 == -73dB */ 209 /* 0110000 == -73dB */
199 /* 0101111 == mute (0x2f) */ 210 /* 0101111 == mute (0x2f) */
200 wm8731_write_masked(LOUTVOL, vol_l, LOUTVOL_LHPVOL_MASK); 211 wmc_write_masked(LOUTVOL, vol_l, WMC_OUT_VOL_MASK);
201 wm8731_write_masked(ROUTVOL, vol_r, ROUTVOL_RHPVOL_MASK); 212 wmc_write_masked(ROUTVOL, vol_r, WMC_OUT_VOL_MASK);
202} 213}
203 214
204/* Nice shutdown of WM8731 codec */ 215/* Nice shutdown of WM codec */
205void audiohw_close(void) 216void audiohw_close(void)
206{ 217{
207 /* POWER DOWN SEQUENCE */ 218 /* POWER DOWN SEQUENCE */
208 /* 1) Set the OUTPD bit to '1' (power down). */ 219 /* 1) Set the OUTPD bit to '1' (power down). */
209 wm8731_set(PDCTRL, PDCTRL_OUTPD); 220 wmc_set(PDCTRL, PDCTRL_OUTPD);
210 /* 2) Remove the WM8731 supplies. */ 221 /* 2) Remove the WM codec supplies. */
211} 222}
212 223
213void audiohw_set_sample_rate(int sampling_control) 224void audiohw_set_sample_rate(int sampling_control)
214{ 225{
215 int rate = 0; 226 int rate;
216 227
217 switch(sampling_control) 228 switch(sampling_control)
218 { 229 {
219 case SAMPR_96: 230 case SAMPR_96:
220 rate = WM8731_USB24_96000HZ; 231 rate = WMC_USB24_96000HZ;
221 break; 232 break;
222 case SAMPR_88: 233 case SAMPR_88:
223 rate = WM8731_USB24_88200HZ; 234 rate = WMC_USB24_88200HZ;
224 break; 235 break;
225 case SAMPR_48: 236 case SAMPR_48:
226 rate = WM8731_USB24_48000HZ; 237 rate = WMC_USB24_48000HZ;
227 break; 238 break;
239 default:
228 case SAMPR_44: 240 case SAMPR_44:
229 rate = WM8731_USB24_44100HZ; 241 rate = WMC_USB24_44100HZ;
230 break; 242 break;
231 case SAMPR_32: 243 case SAMPR_32:
232 rate = WM8731_USB24_32000HZ; 244 rate = WMC_USB24_32000HZ;
233 break; 245 break;
234 case SAMPR_8: 246 case SAMPR_8:
235 rate = WM8731_USB24_8000HZ; 247 rate = WMC_USB24_8000HZ;
236 break; 248 break;
237 } 249 }
238 250
239 codec_set_active(false); 251 codec_set_active(false);
240 wm8731_write(SAMPCTRL, rate); 252 wmc_write(SAMPCTRL, rate);
241 codec_set_active(true); 253 codec_set_active(true);
242} 254}
243 255
244#ifdef HAVE_RECORDING 256#if defined(HAVE_WM8731) && defined(HAVE_RECORDING)
257/* WM8731 only */
245void audiohw_enable_recording(bool source_mic) 258void audiohw_enable_recording(bool source_mic)
246{ 259{
247 /* NOTE: When switching to digital monitoring we will not want 260 /* NOTE: When switching to digital monitoring we will not want
@@ -250,27 +263,27 @@ void audiohw_enable_recording(bool source_mic)
250 codec_set_active(false); 263 codec_set_active(false);
251 264
252 if (source_mic) { 265 if (source_mic) {
253 wm8731_set(LINVOL, LINVOL_LINMUTE); 266 wmc_set(LINVOL, WMC_IN_MUTE);
254 wm8731_set(RINVOL, RINVOL_RINMUTE); 267 wmc_set(RINVOL, WMC_IN_MUTE);
255 268
256 wm8731_write_masked(PDCTRL, PDCTRL_LINEINPD | PDCTRL_DACPD, 269 wmc_write_masked(PDCTRL, PDCTRL_LINEINPD | PDCTRL_DACPD,
257 PDCTRL_LINEINPD | PDCTRL_MICPD | 270 PDCTRL_LINEINPD | PDCTRL_MICPD |
258 PDCTRL_ADCPD | PDCTRL_DACPD); 271 PDCTRL_ADCPD | PDCTRL_DACPD);
259 wm8731_write_masked(AAPCTRL, AAPCTRL_INSEL | AAPCTRL_SIDETONE, 272 wmc_write_masked(AAPCTRL, AAPCTRL_INSEL | AAPCTRL_SIDETONE,
260 AAPCTRL_MUTEMIC | AAPCTRL_INSEL | 273 AAPCTRL_MUTEMIC | AAPCTRL_INSEL |
261 AAPCTRL_BYPASS | AAPCTRL_DACSEL | 274 AAPCTRL_BYPASS | AAPCTRL_DACSEL |
262 AAPCTRL_SIDETONE); 275 AAPCTRL_SIDETONE);
263 } else { 276 } else {
264 wm8731_write_masked(PDCTRL, PDCTRL_MICPD | PDCTRL_DACPD, 277 wmc_write_masked(PDCTRL, PDCTRL_MICPD | PDCTRL_DACPD,
265 PDCTRL_LINEINPD | PDCTRL_MICPD | 278 PDCTRL_LINEINPD | PDCTRL_MICPD |
266 PDCTRL_ADCPD | PDCTRL_DACPD); 279 PDCTRL_ADCPD | PDCTRL_DACPD);
267 wm8731_write_masked(AAPCTRL, AAPCTRL_MUTEMIC | AAPCTRL_BYPASS, 280 wmc_write_masked(AAPCTRL, AAPCTRL_MUTEMIC | AAPCTRL_BYPASS,
268 AAPCTRL_MUTEMIC | AAPCTRL_INSEL | 281 AAPCTRL_MUTEMIC | AAPCTRL_INSEL |
269 AAPCTRL_BYPASS | AAPCTRL_DACSEL | 282 AAPCTRL_BYPASS | AAPCTRL_DACSEL |
270 AAPCTRL_SIDETONE); 283 AAPCTRL_SIDETONE);
271 284
272 wm8731_clear(LINVOL, LINVOL_LINMUTE); 285 wmc_clear(LINVOL, WMC_IN_MUTE);
273 wm8731_clear(RINVOL, RINVOL_RINMUTE); 286 wmc_clear(RINVOL, WMC_IN_MUTE);
274 } 287 }
275 288
276 codec_set_active(true); 289 codec_set_active(true);
@@ -281,21 +294,21 @@ void audiohw_disable_recording(void)
281 codec_set_active(false); 294 codec_set_active(false);
282 295
283 /* Mute line inputs */ 296 /* Mute line inputs */
284 wm8731_set(LINVOL, LINVOL_LINMUTE); 297 wmc_set(LINVOL, WMC_IN_MUTE);
285 wm8731_set(RINVOL, RINVOL_RINMUTE); 298 wmc_set(RINVOL, WMC_IN_MUTE);
286 wm8731_set(AAPCTRL, AAPCTRL_MUTEMIC); 299 wmc_set(AAPCTRL, AAPCTRL_MUTEMIC);
287 300
288 /* Turn off input analog audio paths */ 301 /* Turn off input analog audio paths */
289 wm8731_clear(AAPCTRL, AAPCTRL_BYPASS | AAPCTRL_SIDETONE); 302 wmc_clear(AAPCTRL, AAPCTRL_BYPASS | AAPCTRL_SIDETONE);
290 303
291 /* Set power config */ 304 /* Set power config */
292 wm8731_write_masked(PDCTRL, 305 wmc_write_masked(PDCTRL,
293 PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_ADCPD, 306 PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_ADCPD,
294 PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_DACPD | 307 PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_DACPD |
295 PDCTRL_ADCPD); 308 PDCTRL_ADCPD);
296 309
297 /* Select DAC */ 310 /* Select DAC */
298 wm8731_set(AAPCTRL, AAPCTRL_DACSEL); 311 wmc_set(AAPCTRL, AAPCTRL_DACSEL);
299 312
300 codec_set_active(true); 313 codec_set_active(true);
301} 314}
@@ -306,15 +319,15 @@ void audiohw_set_recvol(int left, int right, int type)
306 { 319 {
307 case AUDIO_GAIN_MIC: 320 case AUDIO_GAIN_MIC:
308 if (left > 0) { 321 if (left > 0) {
309 wm8731_set(AAPCTRL, AAPCTRL_MIC_BOOST); 322 wmc_set(AAPCTRL, AAPCTRL_MIC_BOOST);
310 } 323 }
311 else { 324 else {
312 wm8731_clear(AAPCTRL, AAPCTRL_MIC_BOOST); 325 wmc_clear(AAPCTRL, AAPCTRL_MIC_BOOST);
313 } 326 }
314 break; 327 break;
315 case AUDIO_GAIN_LINEIN: 328 case AUDIO_GAIN_LINEIN:
316 wm8731_write_masked(LINVOL, left, LINVOL_MASK); 329 wmc_write_masked(LINVOL, left, WMC_IN_VOL_MASK);
317 wm8731_write_masked(RINVOL, right, RINVOL_MASK); 330 wmc_write_masked(RINVOL, right, WMC_IN_VOL_MASK);
318 break; 331 break;
319 default: 332 default:
320 return; 333 return;
@@ -324,13 +337,12 @@ void audiohw_set_recvol(int left, int right, int type)
324void audiohw_set_monitor(bool enable) 337void audiohw_set_monitor(bool enable)
325{ 338{
326 if(enable) { 339 if(enable) {
327 wm8731_clear(PDCTRL, PDCTRL_LINEINPD); 340 wmc_clear(PDCTRL, PDCTRL_LINEINPD);
328 wm8731_set(AAPCTRL, AAPCTRL_BYPASS); 341 wmc_set(AAPCTRL, AAPCTRL_BYPASS);
329 } 342 }
330 else { 343 else {
331 wm8731_clear(AAPCTRL, AAPCTRL_BYPASS); 344 wmc_clear(AAPCTRL, AAPCTRL_BYPASS);
332 wm8731_set(PDCTRL, PDCTRL_LINEINPD); 345 wmc_set(PDCTRL, PDCTRL_LINEINPD);
333 } 346 }
334} 347}
335#endif /* HAVE_RECORDING */ 348#endif /* HAVE_WM8731 && HAVE_RECORDING */
336