FS#11417 by Joe Balough: fix audio/tuner on philips hdd6330
[kugel-rb.git] / firmware / drivers / audio / wm8731.c
blob71050454f3f48097ef69a2b2c3c7a9ae6ad85b24
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
28 #include "config.h"
29 #include "logf.h"
30 #include "system.h"
31 #include "string.h"
33 #include "pcm_sampr.h"
35 #include "audio.h"
37 #include "wmcodec.h"
38 #include "sound.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},
53 #endif
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] =
61 #ifdef HAVE_WM8731
62 [LINVOL] = LINVOL_DEFAULT,
63 [RINVOL] = RINVOL_DEFAULT,
64 #endif
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)
73 /* No BYPASS */
74 [AAPCTRL] = AAPCTRL_DEFAULT,
75 /* No CLKOUT or OSC */
76 [PDCTRL] = PDCTRL_DEFAULT,
77 #endif
78 [DAPCTRL] = DAPCTRL_DEFAULT,
79 #ifndef CODEC_SLAVE
80 [AINTFCE] = AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT | AINTFCE_MS,
81 #else
82 [AINTFCE] = AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT,
83 #endif
84 [SAMPCTRL] = SAMPCTRL_DEFAULT,
85 [ACTIVECTRL] = ACTIVECTRL_DEFAULT,
88 static void wmc_write(int reg, unsigned val)
90 if ((unsigned)reg >= WMC_NUM_REGS)
91 return;
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) {
122 return 0x2f;
123 } else {
124 return((db/10)+0x30+73);
128 int sound_val2phys(int setting, int value)
130 int result;
132 switch(setting)
134 #ifdef HAVE_RECORDING
135 case SOUND_LEFT_GAIN:
136 case SOUND_RIGHT_GAIN:
137 result = (value - 23) * 15;
138 break;
139 case SOUND_MIC_GAIN:
140 result = value * 200;
141 break;
142 #endif
143 default:
144 result = value;
145 break;
148 return result;
151 static void audiohw_mute(bool mute)
153 if (mute) {
154 /* Set DACMU = 1 to soft-mute the audio DACs. */
155 wmc_set(DAPCTRL, DAPCTRL_DACMU);
156 } else {
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
173 * all OFF. */
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)
197 sleep(HZ);
199 audiohw_mute(false);
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) || defined(PHILIPS_HDD6330)
205 GPO32_ENABLE |= 0x2;
206 GPO32_VAL &= ~0x2;
207 #endif
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 */
214 /* 1111001 == 0dB */
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)
232 /* For 24MHz MCLK */
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)
252 /* WM8731 only */
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);
260 if (source_mic) {
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 |
270 AAPCTRL_SIDETONE);
271 } else {
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 |
278 AAPCTRL_SIDETONE);
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 |
303 PDCTRL_ADCPD);
305 /* Select DAC */
306 wmc_set(AAPCTRL, AAPCTRL_DACSEL);
308 codec_set_active(true);
311 void audiohw_set_recvol(int left, int right, int type)
313 switch (type)
315 case AUDIO_GAIN_MIC:
316 if (left > 0) {
317 wmc_set(AAPCTRL, AAPCTRL_MIC_BOOST);
319 else {
320 wmc_clear(AAPCTRL, AAPCTRL_MIC_BOOST);
322 break;
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);
326 break;
327 default:
328 return;
332 void audiohw_set_monitor(bool enable)
334 if(enable) {
335 wmc_clear(PDCTRL, PDCTRL_LINEINPD);
336 wmc_set(AAPCTRL, AAPCTRL_BYPASS);
338 else {
339 wmc_clear(AAPCTRL, AAPCTRL_BYPASS);
340 wmc_set(PDCTRL, PDCTRL_LINEINPD);
343 #endif /* HAVE_WM8731 && HAVE_RECORDING */