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"
41 const struct sound_settings_info audiohw_settings
[] = {
42 [SOUND_VOLUME
] = {"dB", 0, 1, -74, 6, -25},
43 /* HAVE_SW_TONE_CONTROLS */
44 [SOUND_BASS
] = {"dB", 0, 1, -24, 24, 0},
45 [SOUND_TREBLE
] = {"dB", 0, 1, -24, 24, 0},
46 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
47 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
48 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
49 #if defined(HAVE_WM8731) && defined(HAVE_RECORDING)
50 [SOUND_LEFT_GAIN
] = {"dB", 1, 1, 0, 31, 23},
51 [SOUND_RIGHT_GAIN
] = {"dB", 1, 1, 0, 31, 23},
52 [SOUND_MIC_GAIN
] = {"dB", 1, 1, 0, 1, 0},
56 /* Init values/shadows
57 * Ignore bit 8 since that only specifies "both" for updating
58 * gains - "RESET" (15h) not included */
59 static unsigned char wmc_regs
[WMC_NUM_REGS
] =
62 [LINVOL
] = LINVOL_DEFAULT
,
63 [RINVOL
] = RINVOL_DEFAULT
,
65 [LOUTVOL
] = LOUTVOL_DEFAULT
| WMC_OUT_ZCEN
,
66 [ROUTVOL
] = LOUTVOL_DEFAULT
| WMC_OUT_ZCEN
,
67 #if defined(HAVE_WM8711) || defined(HAVE_WM8731)
68 /* BYPASS on by default - OFF until needed */
69 [AAPCTRL
] = AAPCTRL_DEFAULT
& ~AAPCTRL_BYPASS
,
70 /* CLKOUT and OSC on by default - OFF unless needed by a target */
71 [PDCTRL
] = PDCTRL_DEFAULT
| PDCTRL_CLKOUTPD
| PDCTRL_OSCPD
,
72 #elif defined(HAVE_WM8721)
74 [AAPCTRL
] = AAPCTRL_DEFAULT
,
75 /* No CLKOUT or OSC */
76 [PDCTRL
] = PDCTRL_DEFAULT
,
78 [DAPCTRL
] = DAPCTRL_DEFAULT
,
80 [AINTFCE
] = AINTFCE_FORMAT_I2S
| AINTFCE_IWL_16BIT
| AINTFCE_MS
,
82 [AINTFCE
] = AINTFCE_FORMAT_I2S
| AINTFCE_IWL_16BIT
,
84 [SAMPCTRL
] = SAMPCTRL_DEFAULT
,
85 [ACTIVECTRL
] = ACTIVECTRL_DEFAULT
,
88 static void wmc_write(int reg
, unsigned val
)
90 if ((unsigned)reg
>= WMC_NUM_REGS
)
93 wmc_regs
[reg
] = (unsigned char)val
;
94 wmcodec_write(reg
, val
);
97 static void wmc_set(int reg
, unsigned bits
)
99 wmc_write(reg
, wmc_regs
[reg
] | bits
);
102 static void wmc_clear(int reg
, unsigned bits
)
104 wmc_write(reg
, wmc_regs
[reg
] & ~bits
);
107 static void wmc_write_masked(int reg
, unsigned bits
, unsigned mask
)
109 wmc_write(reg
, (wmc_regs
[reg
] & ~mask
) | (bits
& mask
));
112 /* convert tenth of dB volume (-730..60) to master volume register value */
113 int tenthdb2master(int db
)
115 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
116 /* 1111111 == +6dB (0x7f) */
117 /* 1111001 == 0dB (0x79) */
118 /* 0110000 == -73dB (0x30 */
119 /* 0101111 == mute (0x2f) */
121 if (db
< VOLUME_MIN
) {
124 return((db
/10)+0x30+73);
128 int sound_val2phys(int setting
, int value
)
134 #ifdef HAVE_RECORDING
135 case SOUND_LEFT_GAIN
:
136 case SOUND_RIGHT_GAIN
:
137 result
= (value
- 23) * 15;
140 result
= value
* 200;
151 static void audiohw_mute(bool mute
)
154 /* Set DACMU = 1 to soft-mute the audio DACs. */
155 wmc_set(DAPCTRL
, DAPCTRL_DACMU
);
157 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
158 wmc_clear(DAPCTRL
, DAPCTRL_DACMU
);
162 static void codec_set_active(int active
)
164 /* set active to 0x0 or 0x1 */
165 wmc_write(ACTIVECTRL
, active
? ACTIVECTRL_ACTIVE
: 0);
168 void audiohw_preinit(void)
170 /* POWER UP SEQUENCE */
171 /* 1) Switch on power supplies. By default the WM codec is in Standby Mode,
172 * the DAC is digitally muted and the Audio Interface and Outputs are
174 wmcodec_write(RESET
, RESET_RESET
);
176 /* 2) Set all required bits in the Power Down register (0Ch) to '0';
177 * EXCEPT the OUTPD bit, this should be set to '1' (Default). */
178 wmc_clear(PDCTRL
, PDCTRL_DACPD
| PDCTRL_POWEROFF
);
180 /* 3) Set required values in all other registers except 12h (Active). */
181 wmc_set(AINTFCE
, 0); /* Set no bits - write init/shadow value */
183 wmc_set(AAPCTRL
, AAPCTRL_DACSEL
);
184 wmc_write(SAMPCTRL
, WMC_USB24_44100HZ
);
186 /* 4) Set the 'Active' bit in register 12h. */
187 codec_set_active(true);
189 /* 5) The last write of the sequence should be setting OUTPD to '0'
190 * (active) in register 0Ch, enabling the DAC signal path, free
191 * of any significant power-up noise. */
192 wmc_clear(PDCTRL
, PDCTRL_OUTPD
);
195 void audiohw_postinit(void)
201 #if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
202 /* We need to enable bit 4 of GPIOL for output for sound on H10 */
203 GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL
, 0x10);
204 #elif defined(PHILIPS_HDD1630)
210 void audiohw_set_master_vol(int vol_l
, int vol_r
)
212 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
213 /* 1111111 == +6dB */
215 /* 0110000 == -73dB */
216 /* 0101111 == mute (0x2f) */
217 wmc_write_masked(LOUTVOL
, vol_l
, WMC_OUT_VOL_MASK
);
218 wmc_write_masked(ROUTVOL
, vol_r
, WMC_OUT_VOL_MASK
);
221 /* Nice shutdown of WM codec */
222 void audiohw_close(void)
224 /* POWER DOWN SEQUENCE */
225 /* 1) Set the OUTPD bit to '1' (power down). */
226 wmc_set(PDCTRL
, PDCTRL_OUTPD
);
227 /* 2) Remove the WM codec supplies. */
230 void audiohw_set_frequency(int fsel
)
233 static const unsigned char srctrl_table
[HW_NUM_FREQ
] =
235 HW_HAVE_8_([HW_FREQ_8
] = WMC_USB24_8000HZ
,)
236 HW_HAVE_32_([HW_FREQ_32
] = WMC_USB24_32000HZ
,)
237 HW_HAVE_44_([HW_FREQ_44
] = WMC_USB24_44100HZ
,)
238 HW_HAVE_48_([HW_FREQ_48
] = WMC_USB24_48000HZ
,)
239 HW_HAVE_88_([HW_FREQ_88
] = WMC_USB24_88200HZ
,)
240 HW_HAVE_96_([HW_FREQ_96
] = WMC_USB24_96000HZ
,)
243 if ((unsigned)fsel
>= HW_NUM_FREQ
)
244 fsel
= HW_FREQ_DEFAULT
;
246 codec_set_active(false);
247 wmc_write(SAMPCTRL
, srctrl_table
[fsel
]);
248 codec_set_active(true);
251 #if defined(HAVE_WM8731) && defined(HAVE_RECORDING)
253 void audiohw_enable_recording(bool source_mic
)
255 /* NOTE: When switching to digital monitoring we will not want
256 * the DAC disabled. */
258 codec_set_active(false);
261 wmc_set(LINVOL
, WMC_IN_MUTE
);
262 wmc_set(RINVOL
, WMC_IN_MUTE
);
264 wmc_write_masked(PDCTRL
, PDCTRL_LINEINPD
| PDCTRL_DACPD
,
265 PDCTRL_LINEINPD
| PDCTRL_MICPD
|
266 PDCTRL_ADCPD
| PDCTRL_DACPD
);
267 wmc_write_masked(AAPCTRL
, AAPCTRL_INSEL
| AAPCTRL_SIDETONE
,
268 AAPCTRL_MUTEMIC
| AAPCTRL_INSEL
|
269 AAPCTRL_BYPASS
| AAPCTRL_DACSEL
|
272 wmc_write_masked(PDCTRL
, PDCTRL_MICPD
| PDCTRL_DACPD
,
273 PDCTRL_LINEINPD
| PDCTRL_MICPD
|
274 PDCTRL_ADCPD
| PDCTRL_DACPD
);
275 wmc_write_masked(AAPCTRL
, AAPCTRL_MUTEMIC
| AAPCTRL_BYPASS
,
276 AAPCTRL_MUTEMIC
| AAPCTRL_INSEL
|
277 AAPCTRL_BYPASS
| AAPCTRL_DACSEL
|
280 wmc_clear(LINVOL
, WMC_IN_MUTE
);
281 wmc_clear(RINVOL
, WMC_IN_MUTE
);
284 codec_set_active(true);
287 void audiohw_disable_recording(void)
289 codec_set_active(false);
291 /* Mute line inputs */
292 wmc_set(LINVOL
, WMC_IN_MUTE
);
293 wmc_set(RINVOL
, WMC_IN_MUTE
);
294 wmc_set(AAPCTRL
, AAPCTRL_MUTEMIC
);
296 /* Turn off input analog audio paths */
297 wmc_clear(AAPCTRL
, AAPCTRL_BYPASS
| AAPCTRL_SIDETONE
);
299 /* Set power config */
300 wmc_write_masked(PDCTRL
,
301 PDCTRL_LINEINPD
| PDCTRL_MICPD
| PDCTRL_ADCPD
,
302 PDCTRL_LINEINPD
| PDCTRL_MICPD
| PDCTRL_DACPD
|
306 wmc_set(AAPCTRL
, AAPCTRL_DACSEL
);
308 codec_set_active(true);
311 void audiohw_set_recvol(int left
, int right
, int type
)
317 wmc_set(AAPCTRL
, AAPCTRL_MIC_BOOST
);
320 wmc_clear(AAPCTRL
, AAPCTRL_MIC_BOOST
);
323 case AUDIO_GAIN_LINEIN
:
324 wmc_write_masked(LINVOL
, left
, WMC_IN_VOL_MASK
);
325 wmc_write_masked(RINVOL
, right
, WMC_IN_VOL_MASK
);
332 void audiohw_set_monitor(bool enable
)
335 wmc_clear(PDCTRL
, PDCTRL_LINEINPD
);
336 wmc_set(AAPCTRL
, AAPCTRL_BYPASS
);
339 wmc_clear(AAPCTRL
, AAPCTRL_BYPASS
);
340 wmc_set(PDCTRL
, PDCTRL_LINEINPD
);
343 #endif /* HAVE_WM8731 && HAVE_RECORDING */