1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Driver for WM8751 audio codec
12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005
15 * Original file: linux/arch/armnommu/mach-ipod/audio.c
17 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version 2
22 * of the License, or (at your option) any later version.
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
25 * KIND, either express or implied.
27 ****************************************************************************/
34 const struct sound_settings_info audiohw_settings
[] = {
35 [SOUND_VOLUME
] = {"dB", 0, 1, -74, 6, -25},
36 [SOUND_BASS
] = {"dB", 1, 15, -60, 90, 0},
37 [SOUND_TREBLE
] = {"dB", 1, 15, -60, 90, 0},
38 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
39 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
40 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
42 /* -17.25dB to 30.0dB in 0.75dB increments 64 steps*/
43 [SOUND_LEFT_GAIN
] = {"dB", 2, 75, -1725, 3000, 0},
44 [SOUND_RIGHT_GAIN
] = {"dB", 2, 75, -1725, 3000, 0},
45 [SOUND_MIC_GAIN
] = {"dB", 2, 75, -1725, 3000, 3000},
47 #ifdef AUDIOHW_HAVE_BASS_CUTOFF
48 [SOUND_BASS_CUTOFF
] = {"Hz", 0, 70, 130, 200, 200},
50 #ifdef AUDIOHW_HAVE_TREBLE_CUTOFF
51 [SOUND_TREBLE_CUTOFF
] = {"kHz", 0, 4, 4, 8, 4},
53 #ifdef AUDIOHW_HAVE_DEPTH_3D
54 [SOUND_DEPTH_3D
] = {"%", 0, 1, 0, 15, 0},
58 static uint16_t wmcodec_regs
[WM_NUM_REGS
] =
60 [0 ... WM_NUM_REGS
-1] = 0x200, /* set invalid data in gaps */
84 [ADDITIONAL1
] = 0x0c0,
85 [ADDITIONAL2
] = 0x000,
88 [ADDITIONAL3
] = 0x000,
105 /* global prescaler vars */
106 static int prescalertone
= 0;
107 static int prescaler3d
= 0;
109 static void wmcodec_set_reg(unsigned int reg
, unsigned int val
)
111 if (reg
>= WM_NUM_REGS
|| (wmcodec_regs
[reg
] & 0x200))
112 /* invalid register */
115 wmcodec_regs
[reg
] = val
& 0x1ff;
116 wmcodec_write(reg
, wmcodec_regs
[reg
]);
119 static void wmcodec_set_bits(unsigned int reg
, unsigned int bits
)
121 wmcodec_set_reg(reg
, wmcodec_regs
[reg
] | bits
);
124 static void wmcodec_clear_bits(unsigned int reg
, unsigned int bits
)
126 wmcodec_set_reg(reg
, wmcodec_regs
[reg
] & ~bits
);
129 static void wmcodec_set_masked(unsigned int reg
, unsigned int val
,
132 wmcodec_set_reg(reg
, (wmcodec_regs
[reg
] & ~mask
) | val
);
135 /* convert tenth of dB volume (-730..60) to master volume register value */
136 int tenthdb2master(int db
)
138 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
139 /* 1111111 == +6dB (0x7f) */
140 /* 1111001 == 0dB (0x79) */
141 /* 0110000 == -73dB (0x30) */
142 /* 0101111..0000000 == mute (<= 0x2f) */
146 return (db
/ 10) + 73 + 0x30;
149 static int tone_tenthdb2hw(int value
)
151 /* -6.0db..+0db..+9.0db step 1.5db - translate -60..+0..+90 step 15
154 value
= 10 - (value
+ 60) / 15;
157 value
= 0xf; /* 0db -> off */
162 #ifdef AUDIOHW_HAVE_BASS_CUTOFF
163 void audiohw_set_bass_cutoff(int val
)
166 wmcodec_clear_bits(BASSCTRL
, BASSCTRL_BC
);
168 wmcodec_set_bits(BASSCTRL
, BASSCTRL_BC
);
173 #ifdef AUDIOHW_HAVE_TREBLE_CUTOFF
174 void audiohw_set_treble_cutoff(int val
)
177 wmcodec_clear_bits(TREBCTRL
, TREBCTRL_TC
);
179 wmcodec_set_bits(TREBCTRL
, TREBCTRL_TC
);
183 #ifdef HAVE_RECORDING
184 static int recvol2hw(int value
)
186 /* -1725 to 3000 => 0 ... 23 ... 63 */
187 return ((4 * value
) / 300) + 23;
191 int sound_val2phys(int setting
, int value
)
197 #ifdef AUDIOHW_HAVE_DEPTH_3D
199 result
= (100 * value
+ 8) / 15;
209 static void audiohw_mute(bool mute
)
211 /* Mute: Set DACMU = 1 to soft-mute the audio DACs. */
212 /* Unmute: Set DACMU = 0 to soft-un-mute the audio DACs. */
214 wmcodec_set_bits(DACCTRL
, DACCTRL_DACMU
);
216 wmcodec_clear_bits(DACCTRL
, DACCTRL_DACMU
);
219 /* Reset and power up the WM8751 */
220 void audiohw_preinit(void)
223 /* controls headphone ouput */
224 GPIOL_ENABLE
|= 0x10;
225 GPIOL_OUTPUT_EN
|= 0x10;
226 GPIOL_OUTPUT_VAL
|= 0x10; /* disable */
230 /* control headphone output
231 * disabled on startup
233 and_l(~(1<<25),&GPIO1_OUT
);
234 or_l((1<<25), &GPIO1_ENABLE
);
235 or_l((1<<25), &GPIO1_FUNCTION
);
239 * 1. Switch on power supplies.
240 * By default the WM8751 is in Standby Mode, the DAC is
241 * digitally muted and the Audio Interface, Line outputs
242 * and Headphone outputs are all OFF (DACMU = 1 Power
243 * Management registers 1 and 2 are all zeros).
246 wmcodec_write(RESET
, RESET_RESET
); /*Reset*/
248 /* 2. Enable Vmid and VREF. */
249 wmcodec_set_bits(PWRMGMT1
, PWRMGMT1_VREF
| PWRMGMT1_VMIDSEL_5K
);
252 wmcodec_set_bits(AINTFCE
,AINTFCE_WL_16
| AINTFCE_FORMAT_I2S
);
254 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */
255 /* IWL=00(16 bit) FORMAT=10(I2S format) */
256 wmcodec_set_bits(AINTFCE
, AINTFCE_MS
| AINTFCE_WL_16
|
259 /* Set default samplerate */
261 audiohw_set_frequency(HW_FREQ_DEFAULT
);
264 /* Enable DACs and audio output after a short delay */
265 void audiohw_postinit(void)
267 /* From app notes: allow Vref to stabilize to reduce clicks */
270 #ifdef AUDIOHW_HAVE_DEPTH_3D
271 wmcodec_set_bits(ENHANCE_3D
, ENHANCE_3D_MODE3D_PLAYBACK
);
274 /* 3. Enable DACs as required. */
275 wmcodec_set_bits(PWRMGMT2
, PWRMGMT2_DACL
| PWRMGMT2_DACR
);
277 /* 4. Enable line and / or headphone output buffers as required. */
278 #if defined(GIGABEAT_F)
279 /* headphones + line-out */
280 wmcodec_set_bits(PWRMGMT2
, PWRMGMT2_LOUT1
| PWRMGMT2_ROUT1
|
281 PWRMGMT2_LOUT2
| PWRMGMT2_ROUT2
);
284 wmcodec_set_bits(PWRMGMT2
, PWRMGMT2_LOUT1
| PWRMGMT2_ROUT1
);
287 /* Full -0dB on the DACS */
288 wmcodec_set_bits(LEFTGAIN
, 0xff);
289 wmcodec_set_bits(RIGHTGAIN
, RIGHTGAIN_RDVU
| 0xff);
291 /* Enable Thermal shutdown, Timeout when zero-crossing in use,
292 * set analog bias for 3.3V, monomix to DACR
294 wmcodec_set_reg(ADDITIONAL1
, ADDITIONAL1_TSDEN
| ADDITIONAL1_TOEN
|
295 ADDITIONAL1_DMONOMIX_LLRR
| ADDITIONAL1_VSEL_DEFAULT
);
298 /* Enable zero-crossing in out stage */
299 wmcodec_set_bits(LOUT1
, LOUT1_LO1ZC
);
300 wmcodec_set_bits(ROUT1
, ROUT1_RO1ZC
);
301 wmcodec_set_bits(LOUT2
, LOUT2_LO2ZC
);
302 wmcodec_set_bits(ROUT2
, ROUT2_RO2ZC
);
304 /* route signal from DAC to mixers */
305 wmcodec_set_bits(LEFTMIX1
, LEFTMIX1_LD2LO
);
306 wmcodec_set_bits(RIGHTMIX2
, RIGHTMIX2_RD2RO
);
308 #ifdef TOSHIBA_GIGABEAT_F
309 #ifdef HAVE_HARDWARE_BEEP
310 /* Single-ended mono input */
311 wmcodec_set_reg(MONOMIX1
, 0x00);
313 /* Route mono input to both outputs at 0dB */
314 wmcodec_set_reg(LEFTMIX2
, LEFTMIX2_MI2LO
| LEFTMIX2_MI2LOVOL(2));
315 wmcodec_set_reg(RIGHTMIX1
, RIGHTMIX1_MI2RO
| RIGHTMIX1_MI2ROVOL(2));
319 /* lower power consumption */
320 wmcodec_set_masked(PWRMGMT1
, PWRMGMT1_VMIDSEL_50K
,
321 PWRMGMT1_VMIDSEL_MASK
);
326 /* enable headphone output */
327 GPIOL_OUTPUT_VAL
&= ~0x10;
328 GPIOL_OUTPUT_EN
|= 0x10;
332 /* enable headphone output */
333 or_l((1<<25),&GPIO1_OUT
);
337 void audiohw_set_master_vol(int vol_l
, int vol_r
)
339 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
340 /* 1111111 == +6dB */
342 /* 0110000 == -73dB */
343 /* 0101111 == mute (0x2f) */
345 wmcodec_set_masked(LOUT1
, LOUT1_LOUT1VOL(vol_l
),
346 LOUT1_LOUT1VOL_MASK
);
347 wmcodec_set_masked(ROUT1
, ROUT1_RO1VU
| ROUT1_ROUT1VOL(vol_r
),
348 ROUT1_ROUT1VOL_MASK
);
351 #ifdef TOSHIBA_GIGABEAT_F
352 void audiohw_set_lineout_vol(int vol_l
, int vol_r
)
354 wmcodec_set_masked(LOUT2
, LOUT2_LOUT2VOL(vol_l
),
355 LOUT2_LOUT2VOL_MASK
);
356 wmcodec_set_masked(ROUT2
, ROUT2_RO2VU
| ROUT2_ROUT2VOL(vol_r
),
357 ROUT2_ROUT2VOL_MASK
);
361 void audiohw_set_bass(int value
)
363 wmcodec_set_masked(BASSCTRL
,
364 BASSCTRL_BASS(tone_tenthdb2hw(value
)),
368 void audiohw_set_treble(int value
)
370 wmcodec_set_masked(TREBCTRL
, TREBCTRL_TREB(tone_tenthdb2hw(value
)),
374 static void sync_prescaler(void)
377 prescaler
= prescalertone
+ prescaler3d
;
379 /* attenuate in 0.5dB steps (0dB - -127dB) */
380 wmcodec_set_reg(LEFTGAIN
, 0xff - (prescaler
& LEFTGAIN_LDACVOL
));
381 wmcodec_set_reg(RIGHTGAIN
, RIGHTGAIN_RDVU
|
382 (0xff - (prescaler
& RIGHTGAIN_RDACVOL
)));
385 void audiohw_set_prescaler(int value
)
387 prescalertone
= 3 * value
/ 15; /* value in tdB */
391 /* Nice shutdown of WM8751 codec */
392 void audiohw_close(void)
394 /* 1. Set DACMU = 1 to soft-mute the audio DACs. */
398 /* disable headphone out */
399 and_l(~(1<<25), &GPIO1_OUT
);
402 /* 2. Disable all output buffers. */
403 wmcodec_set_reg(PWRMGMT2
, 0x0);
405 /* 3. Switch off the power supplies. */
406 wmcodec_set_reg(PWRMGMT1
, 0x0);
409 /* According to datasheet of WM8750
410 * clocking setup is needed in both slave and master mode
412 void audiohw_set_frequency(int fsel
)
415 static const unsigned char srctrl_table
[HW_NUM_FREQ
] =
417 HW_HAVE_11_([HW_FREQ_11
] = CODEC_SRCTRL_11025HZ
,)
418 HW_HAVE_22_([HW_FREQ_22
] = CODEC_SRCTRL_22050HZ
,)
419 HW_HAVE_44_([HW_FREQ_44
] = CODEC_SRCTRL_44100HZ
,)
420 HW_HAVE_88_([HW_FREQ_88
] = CODEC_SRCTRL_88200HZ
,)
423 if ((unsigned)fsel
>= HW_NUM_FREQ
)
424 fsel
= HW_FREQ_DEFAULT
;
426 wmcodec_set_reg(CLOCKING
, srctrl_table
[fsel
]);
430 #ifdef AUDIOHW_HAVE_DEPTH_3D
431 /* Set the depth of the 3D effect */
432 void audiohw_set_depth_3d(int val
)
436 wmcodec_set_bits(ENHANCE_3D
, ENHANCE_3D_3DEN
);
437 wmcodec_set_masked(ENHANCE_3D
, ENHANCE_3D_DEPTH(val
),
438 ENHANCE_3D_DEPTH_MASK
);
442 wmcodec_clear_bits(ENHANCE_3D
, ENHANCE_3D_3DEN
);
445 /* -4 dB @ full setting
446 * this gives approximately constant volume on setting change
447 * and prevents clipping (at least on my HD300)
449 prescaler3d
= 8*val
/ 15;
454 #ifdef HAVE_RECORDING
456 static void audiohw_set_ngat(int ngath
, int type
, bool enable
)
458 /* This function controls Noise gate function
459 * of the codec. This can only run in conjunction
464 wmcodec_set_reg(NGAT
, NGAT_NGG(type
) |
465 NGAT_NGTH(ngath
) | NGAT_NGAT
);
467 wmcodec_clear_bits(NGAT
, NGAT_NGAT
);
471 static void audiohw_set_alc(unsigned char level
, /* signal level at ADC */
472 bool zc
, /* zero cross detection */
473 unsigned char hold
, /* hold time */
474 unsigned char decay
, /* decay time */
475 unsigned char attack
, /* attack time */
476 bool enable
) /* hw function on/off */
480 wmcodec_set_reg(ALC1
, ALC1_ALCSEL_STEREO
| ALC1_MAXGAIN(0x07) |
482 wmcodec_set_reg(ALC2
, zc
?ALC2_ALCZC
:0 | ALC2_HLD(hold
));
483 wmcodec_set_reg(ALC3
, ALC3_DCY(decay
) | ALC3_ATK(attack
));
487 wmcodec_set_masked(ALC1
, ALC1_ALCSEL_DISABLED
, ALC1_ALCSEL_MASK
);
492 void audiohw_set_recsrc(int source
, bool recording
)
498 * if recording == false we use analog bypass from input
499 * turn off ADC, PGA to save power
500 * turn on output buffer(s)
502 * if recording == true we route input signal to PGA
503 * and monitoring picks up signal after PGA and ADC
504 * turn on ADC, PGA, DAC, output buffer(s)
509 case AUDIO_SRC_PLAYBACK
:
512 /* mute PGA, disable all audio paths but DAC and output stage*/
513 wmcodec_set_bits(LINVOL
, LINVOL_LINMUTE
); /* Mute */
514 wmcodec_set_bits(RINVOL
, RINVOL_RINMUTE
); /* Mute */
516 wmcodec_clear_bits(PWRMGMT2
, PWRMGMT2_OUT3
| PWRMGMT2_MOUT
|
517 PWRMGMT2_ROUT2
| PWRMGMT2_LOUT2
);
519 /* route DAC signal to output mixer, disable INPUT routing */
520 wmcodec_clear_bits(LEFTMIX1
, LEFTMIX1_LI2LO
);
521 wmcodec_set_bits(LEFTMIX1
, LEFTMIX1_LD2LO
);
522 wmcodec_clear_bits(RIGHTMIX2
, RIGHTMIX2_RI2RO
);
523 wmcodec_set_bits(RIGHTMIX2
, RIGHTMIX2_RD2RO
);
529 case AUDIO_SRC_FMRADIO
:
533 /* Turn on PGA and ADC */
534 wmcodec_set_bits(PWRMGMT1
, PWRMGMT1_AINL
| PWRMGMT1_AINR
|
535 PWRMGMT1_ADCL
| PWRMGMT1_ADCR
);
537 /* Setup input source for PGA as INPUT1 */
538 wmcodec_set_masked(ADCL
, ADCL_LINSEL_LINPUT1
, ADCL_LINSEL_MASK
);
539 wmcodec_set_masked(ADCR
, ADCR_RINSEL_RINPUT1
, ADCR_RINSEL_MASK
);
541 /* turn off ALC and NGAT as OF do */
543 audiohw_set_alc(0x00, false, 0x00, 0x00, 0x00, false);
544 audiohw_set_ngat(0x00, 0x00, false);
547 /* setup output digital data
548 * default is LADC -> LDATA, RADC -> RDATA
549 * so we don't touch this
552 /* skip: power up DAC and output stage as its never powered down
553 wmcodec_set_bits(PWRMGMT2, PWRMGMT2_DACL | PWRMGMT2_DACR |
554 PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1);
557 /* route DAC signal to output mixer, disable INPUT routing */
558 wmcodec_clear_bits(LEFTMIX1
, LEFTMIX1_LI2LO
);
559 wmcodec_set_bits(LEFTMIX1
, LEFTMIX1_LD2LO
);
560 wmcodec_clear_bits(RIGHTMIX2
, RIGHTMIX2_RI2RO
);
561 wmcodec_set_bits(RIGHTMIX2
, RIGHTMIX2_RD2RO
);
569 /* turn off ADC, PGA */
570 wmcodec_clear_bits(PWRMGMT1
, PWRMGMT1_AINL
| PWRMGMT1_AINR
|
571 PWRMGMT1_ADCL
| PWRMGMT1_ADCR
);
573 /* setup monitor mode by routing input signal to outmix
576 wmcodec_set_masked(LEFTMIX1
, LEFTMIX1_LI2LOVOL(0x20),
577 LEFTMIX1_LI2LOVOL_MASK
);
578 wmcodec_set_bits(LEFTMIX1
, LEFTMIX1_LI2LO
|
579 LEFTMIX1_LMIXSEL_LINPUT1
|
581 wmcodec_set_masked(RIGHTMIX2
, RIGHTMIX2_RI2ROVOL(0x20),
582 RIGHTMIX2_RI2ROVOL_MASK
);
583 wmcodec_set_bits(RIGHTMIX1
, RIGHTMIX1_RMIXSEL_RINPUT1
);
584 wmcodec_set_bits(RIGHTMIX2
, RIGHTMIX2_RI2RO
|
591 #if (INPUT_SRC_CAPS & SRC_CAP_LINEIN)
592 case AUDIO_SRC_LINEIN
:
595 /* Turn on PGA, ADC */
596 wmcodec_set_bits(PWRMGMT1
, PWRMGMT1_AINL
| PWRMGMT1_AINR
|
597 PWRMGMT1_ADCL
| PWRMGMT1_ADCR
);
599 /* Setup input source for PGA as INPUT2
602 wmcodec_set_masked(ADCL
, ADCL_LINSEL_LINPUT2
, ADCL_LINSEL_MASK
);
603 wmcodec_set_masked(ADCR
, ADCR_RINSEL_RINPUT2
, ADCR_RINSEL_MASK
);
605 /* setup ALC and NGAT as OF do */
606 /* level, zc, hold, decay, attack, enable */
607 /* audiohw_set_alc(0x0b, true, 0x00, 0x03, 0x02, true); */
608 /* ngath, type, enable */
609 /* audiohw_set_ngat(0x08, 0x02, true); */
611 /* setup output digital data
612 * default is LADC -> LDATA, RADC -> RDATA
613 * so we don't touch this
616 /* route DAC signal to output mixer, disable INPUT routing */
617 wmcodec_clear_bits(LEFTMIX1
, LEFTMIX1_LI2LO
);
618 wmcodec_set_bits(LEFTMIX1
, LEFTMIX1_LD2LO
);
619 wmcodec_clear_bits(RIGHTMIX2
, RIGHTMIX2_RI2RO
);
620 wmcodec_set_bits(RIGHTMIX2
, RIGHTMIX2_RD2RO
);
622 #if !defined(MPIO_HD300)
623 /* HD300 uses the same socket for headphones and line-in */
628 #if (INPUT_SRC_CAPS & SRC_CAP_MIC)
632 /* Turn on PGA and ADC */
633 wmcodec_set_bits(PWRMGMT1
, PWRMGMT1_AINL
| PWRMGMT1_AINR
|
634 PWRMGMT1_ADCL
| PWRMGMT1_ADCR
);
636 /* Setup input source for PGA as INPUT3
639 wmcodec_set_masked(ADCL
, ADCL_LINSEL_LINPUT3
, ADCL_LINSEL_MASK
);
640 wmcodec_set_masked(ADCR
, ADCR_RINSEL_RINPUT3
, ADCR_RINSEL_MASK
);
642 /* setup ALC and NGAT as OF do */
643 /* level, zc, hold, decay, attack, enable */
644 /* audiohw_set_alc(0x0f, false, 0x00, 0x05, 0x02, true); */
645 /* ngath, type, enable */
646 /* audiohw_set_ngat(0x1f, 0x00, true); */
648 /* setup output digital data
649 * default is LADC -> LDATA, RADC -> RDATA
650 * so we don't touch this
653 /* route DAC signal to output mixer, disable INPUT routing */
654 wmcodec_clear_bits(LEFTMIX1
, LEFTMIX1_LI2LO
);
655 wmcodec_set_bits(LEFTMIX1
, LEFTMIX1_LD2LO
);
656 wmcodec_clear_bits(RIGHTMIX2
, RIGHTMIX2_RI2RO
);
657 wmcodec_set_bits(RIGHTMIX2
, RIGHTMIX2_RD2RO
);
662 } /* switch(source) */
666 void audiohw_set_recvol(int vol_l
, int vol_r
, int type
)
668 wmcodec_set_reg(LINVOL
, LINVOL_LIZC
| LINVOL_LINVOL(recvol2hw(vol_l
)));
670 if (type
== AUDIO_GAIN_MIC
)
671 wmcodec_set_reg(RINVOL
, RINVOL_RIVU
| RINVOL_RIZC
|
672 RINVOL_RINVOL(recvol2hw(vol_l
)));
674 wmcodec_set_reg(RINVOL
, RINVOL_RIVU
| RINVOL_RIZC
|
675 RINVOL_RINVOL(recvol2hw(vol_r
)));
677 #endif /* HAVE_RECORDING */
678 #endif /* HAVE_WM8750 */