1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Driver for WM8711/WM8721/WM8731 audio codecs
12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in January 2006
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 ****************************************************************************/
33 #include "pcm_sampr.h"
42 const struct sound_settings_info audiohw_settings
[] = {
43 [SOUND_VOLUME
] = {"dB", 0, 1, -74, 6, -25},
44 /* HAVE_SW_TONE_CONTROLS */
45 [SOUND_BASS
] = {"dB", 0, 1, -24, 24, 0},
46 [SOUND_TREBLE
] = {"dB", 0, 1, -24, 24, 0},
47 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
48 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
49 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
50 #if defined(HAVE_WM8731) && defined(HAVE_RECORDING)
51 [SOUND_LEFT_GAIN
] = {"dB", 1, 1, 0, 31, 23},
52 [SOUND_RIGHT_GAIN
] = {"dB", 1, 1, 0, 31, 23},
53 [SOUND_MIC_GAIN
] = {"dB", 1, 1, 0, 1, 0},
57 /* Init values/shadows
58 * Ignore bit 8 since that only specifies "both" for updating
59 * gains - "RESET" (15h) not included */
60 static unsigned char wmc_regs
[WMC_NUM_REGS
] =
63 [LINVOL
] = LINVOL_DEFAULT
,
64 [RINVOL
] = RINVOL_DEFAULT
,
66 [LOUTVOL
] = LOUTVOL_DEFAULT
| WMC_OUT_ZCEN
,
67 [ROUTVOL
] = LOUTVOL_DEFAULT
| WMC_OUT_ZCEN
,
68 #if defined(HAVE_WM8711) || defined(HAVE_WM8731)
69 /* BYPASS on by default - OFF until needed */
70 [AAPCTRL
] = AAPCTRL_DEFAULT
& ~AAPCTRL_BYPASS
,
71 /* CLKOUT and OSC on by default - OFF unless needed by a target */
72 [PDCTRL
] = PDCTRL_DEFAULT
| PDCTRL_CLKOUTPD
| PDCTRL_OSCPD
,
73 #elif defined(HAVE_WM8721)
75 [AAPCTRL
] = AAPCTRL_DEFAULT
,
76 /* No CLKOUT or OSC */
77 [PDCTRL
] = PDCTRL_DEFAULT
,
79 [DAPCTRL
] = DAPCTRL_DEFAULT
,
81 [AINTFCE
] = AINTFCE_FORMAT_I2S
| AINTFCE_IWL_16BIT
| AINTFCE_MS
,
83 [AINTFCE
] = AINTFCE_FORMAT_I2S
| AINTFCE_IWL_16BIT
,
85 [SAMPCTRL
] = SAMPCTRL_DEFAULT
,
86 [ACTIVECTRL
] = ACTIVECTRL_DEFAULT
,
89 static void wmc_write(int reg
, unsigned val
)
91 if ((unsigned)reg
>= WMC_NUM_REGS
)
94 wmc_regs
[reg
] = (unsigned char)val
;
95 wmcodec_write(reg
, val
);
98 static void wmc_set(int reg
, unsigned bits
)
100 wmc_write(reg
, wmc_regs
[reg
] | bits
);
103 static void wmc_clear(int reg
, unsigned bits
)
105 wmc_write(reg
, wmc_regs
[reg
] & ~bits
);
108 static void wmc_write_masked(int reg
, unsigned bits
, unsigned mask
)
110 wmc_write(reg
, (wmc_regs
[reg
] & ~mask
) | (bits
& mask
));
113 /* convert tenth of dB volume (-730..60) to master volume register value */
114 int tenthdb2master(int db
)
116 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
117 /* 1111111 == +6dB (0x7f) */
118 /* 1111001 == 0dB (0x79) */
119 /* 0110000 == -73dB (0x30 */
120 /* 0101111 == mute (0x2f) */
122 if (db
< VOLUME_MIN
) {
125 return((db
/10)+0x30+73);
129 int sound_val2phys(int setting
, int value
)
135 #ifdef HAVE_RECORDING
136 case SOUND_LEFT_GAIN
:
137 case SOUND_RIGHT_GAIN
:
138 result
= (value
- 23) * 15;
141 result
= value
* 200;
152 static void audiohw_mute(bool mute
)
155 /* Set DACMU = 1 to soft-mute the audio DACs. */
156 wmc_set(DAPCTRL
, DAPCTRL_DACMU
);
158 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
159 wmc_clear(DAPCTRL
, DAPCTRL_DACMU
);
163 static void codec_set_active(int active
)
165 /* set active to 0x0 or 0x1 */
166 wmc_write(ACTIVECTRL
, active
? ACTIVECTRL_ACTIVE
: 0);
169 void audiohw_preinit(void)
171 /* POWER UP SEQUENCE */
172 /* 1) Switch on power supplies. By default the WM codec is in Standby Mode,
173 * the DAC is digitally muted and the Audio Interface and Outputs are
175 wmcodec_write(RESET
, RESET_RESET
);
177 /* 2) Set all required bits in the Power Down register (0Ch) to '0';
178 * EXCEPT the OUTPD bit, this should be set to '1' (Default). */
179 wmc_clear(PDCTRL
, PDCTRL_DACPD
| PDCTRL_POWEROFF
);
181 /* 3) Set required values in all other registers except 12h (Active). */
182 wmc_set(AINTFCE
, 0); /* Set no bits - write init/shadow value */
184 wmc_set(AAPCTRL
, AAPCTRL_DACSEL
);
185 wmc_write(SAMPCTRL
, WMC_USB24_44100HZ
);
187 /* 4) Set the 'Active' bit in register 12h. */
188 codec_set_active(true);
190 /* 5) The last write of the sequence should be setting OUTPD to '0'
191 * (active) in register 0Ch, enabling the DAC signal path, free
192 * of any significant power-up noise. */
193 wmc_clear(PDCTRL
, PDCTRL_OUTPD
);
196 void audiohw_postinit(void)
202 #if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
203 /* We need to enable bit 4 of GPIOL for output for sound on H10 */
204 GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL
, 0x10);
205 #elif defined(PHILIPS_HDD1630)
211 void audiohw_set_master_vol(int vol_l
, int vol_r
)
213 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
214 /* 1111111 == +6dB */
216 /* 0110000 == -73dB */
217 /* 0101111 == mute (0x2f) */
218 wmc_write_masked(LOUTVOL
, vol_l
, WMC_OUT_VOL_MASK
);
219 wmc_write_masked(ROUTVOL
, vol_r
, WMC_OUT_VOL_MASK
);
222 /* Nice shutdown of WM codec */
223 void audiohw_close(void)
225 /* POWER DOWN SEQUENCE */
226 /* 1) Set the OUTPD bit to '1' (power down). */
227 wmc_set(PDCTRL
, PDCTRL_OUTPD
);
228 /* 2) Remove the WM codec supplies. */
231 void audiohw_set_frequency(int fsel
)
234 static const unsigned char srctrl_table
[HW_NUM_FREQ
] =
236 HW_HAVE_8_([HW_FREQ_8
] = WMC_USB24_8000HZ
,)
237 HW_HAVE_32_([HW_FREQ_32
] = WMC_USB24_32000HZ
,)
238 HW_HAVE_44_([HW_FREQ_44
] = WMC_USB24_44100HZ
,)
239 HW_HAVE_48_([HW_FREQ_48
] = WMC_USB24_48000HZ
,)
240 HW_HAVE_88_([HW_FREQ_88
] = WMC_USB24_88200HZ
,)
241 HW_HAVE_96_([HW_FREQ_96
] = WMC_USB24_96000HZ
,)
244 if ((unsigned)fsel
>= HW_NUM_FREQ
)
245 fsel
= HW_FREQ_DEFAULT
;
247 codec_set_active(false);
248 wmc_write(SAMPCTRL
, srctrl_table
[fsel
]);
249 codec_set_active(true);
252 #if defined(HAVE_WM8731) && defined(HAVE_RECORDING)
254 void audiohw_enable_recording(bool source_mic
)
256 /* NOTE: When switching to digital monitoring we will not want
257 * the DAC disabled. */
259 codec_set_active(false);
262 wmc_set(LINVOL
, WMC_IN_MUTE
);
263 wmc_set(RINVOL
, WMC_IN_MUTE
);
265 wmc_write_masked(PDCTRL
, PDCTRL_LINEINPD
| PDCTRL_DACPD
,
266 PDCTRL_LINEINPD
| PDCTRL_MICPD
|
267 PDCTRL_ADCPD
| PDCTRL_DACPD
);
268 wmc_write_masked(AAPCTRL
, AAPCTRL_INSEL
| AAPCTRL_SIDETONE
,
269 AAPCTRL_MUTEMIC
| AAPCTRL_INSEL
|
270 AAPCTRL_BYPASS
| AAPCTRL_DACSEL
|
273 wmc_write_masked(PDCTRL
, PDCTRL_MICPD
| PDCTRL_DACPD
,
274 PDCTRL_LINEINPD
| PDCTRL_MICPD
|
275 PDCTRL_ADCPD
| PDCTRL_DACPD
);
276 wmc_write_masked(AAPCTRL
, AAPCTRL_MUTEMIC
| AAPCTRL_BYPASS
,
277 AAPCTRL_MUTEMIC
| AAPCTRL_INSEL
|
278 AAPCTRL_BYPASS
| AAPCTRL_DACSEL
|
281 wmc_clear(LINVOL
, WMC_IN_MUTE
);
282 wmc_clear(RINVOL
, WMC_IN_MUTE
);
285 codec_set_active(true);
288 void audiohw_disable_recording(void)
290 codec_set_active(false);
292 /* Mute line inputs */
293 wmc_set(LINVOL
, WMC_IN_MUTE
);
294 wmc_set(RINVOL
, WMC_IN_MUTE
);
295 wmc_set(AAPCTRL
, AAPCTRL_MUTEMIC
);
297 /* Turn off input analog audio paths */
298 wmc_clear(AAPCTRL
, AAPCTRL_BYPASS
| AAPCTRL_SIDETONE
);
300 /* Set power config */
301 wmc_write_masked(PDCTRL
,
302 PDCTRL_LINEINPD
| PDCTRL_MICPD
| PDCTRL_ADCPD
,
303 PDCTRL_LINEINPD
| PDCTRL_MICPD
| PDCTRL_DACPD
|
307 wmc_set(AAPCTRL
, AAPCTRL_DACSEL
);
309 codec_set_active(true);
312 void audiohw_set_recvol(int left
, int right
, int type
)
318 wmc_set(AAPCTRL
, AAPCTRL_MIC_BOOST
);
321 wmc_clear(AAPCTRL
, AAPCTRL_MIC_BOOST
);
324 case AUDIO_GAIN_LINEIN
:
325 wmc_write_masked(LINVOL
, left
, WMC_IN_VOL_MASK
);
326 wmc_write_masked(RINVOL
, right
, WMC_IN_VOL_MASK
);
333 void audiohw_set_monitor(bool enable
)
336 wmc_clear(PDCTRL
, PDCTRL_LINEINPD
);
337 wmc_set(AAPCTRL
, AAPCTRL_BYPASS
);
340 wmc_clear(AAPCTRL
, AAPCTRL_BYPASS
);
341 wmc_set(PDCTRL
, PDCTRL_LINEINPD
);
344 #endif /* HAVE_WM8731 && HAVE_RECORDING */