Hopefully finish off the red from r26051.
[kugel-rb.git] / firmware / drivers / audio / wm8985.c
blobda08b444023da2e31fc9698313ef58a51fadce35
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "logf.h"
20 #include "system.h"
21 #include "string.h"
22 #include "audio.h"
24 #include "wmcodec.h"
25 #include "audiohw.h"
27 /* Register addresses as per datasheet Rev.4.4 */
28 #define RESET 0x00
29 #define PWRMGMT1 0x01
30 #define PWRMGMT2 0x02
31 #define PWRMGMT3 0x03
32 #define AINTFCE 0x04
33 #define COMPAND 0x05
34 #define CLKGEN 0x06
35 #define SRATECTRL 0x07
36 #define GPIOCTL 0x08
37 #define JACKDETECT0 0x09
38 #define DACCTRL 0x0a
39 #define LDACVOL 0x0b
40 #define RDACVOL 0x0c
41 #define JACKDETECT1 0x0d
42 #define ADCCTL 0x0e
43 #define LADCVOL 0x0f
44 #define RADCVOL 0x10
46 #define EQ1 0x12
47 #define EQ2 0x13
48 #define EQ3 0x14
49 #define EQ4 0x15
50 #define EQ5 0x16
51 #define EQ_GAIN_MASK 0x001f
52 #define EQ_CUTOFF_MASK 0x0060
53 #define EQ_GAIN_VALUE(x) (((-x) + 12) & 0x1f)
54 #define EQ_CUTOFF_VALUE(x) ((((x) - 1) & 0x03) << 5)
56 #define CLASSDCTL 0x17
57 #define DACLIMIT1 0x18
58 #define DACLIMIT2 0x19
59 #define NOTCH1 0x1b
60 #define NOTCH2 0x1c
61 #define NOTCH3 0x1d
62 #define NOTCH4 0x1e
63 #define ALCCTL1 0x20
64 #define ALCCTL2 0x21
65 #define ALCCTL3 0x22
66 #define NOISEGATE 0x23
67 #define PLLN 0x24
68 #define PLLK1 0x25
69 #define PLLK2 0x26
70 #define PLLK3 0x27
71 #define THREEDCTL 0x29
72 #define OUT4ADC 0x2a
73 #define BEEPCTRL 0x2b
74 #define INCTRL 0x2c
75 #define LINPGAGAIN 0x2d
76 #define RINPGAGAIN 0x2e
77 #define LADCBOOST 0x2f
78 #define RADCBOOST 0x30
79 #define OUTCTRL 0x31
80 #define LOUTMIX 0x32
81 #define ROUTMIX 0x33
82 #define LOUT1VOL 0x34
83 #define ROUT1VOL 0x35
84 #define LOUT2VOL 0x36
85 #define ROUT2VOL 0x37
86 #define OUT3MIX 0x38
87 #define OUT4MIX 0x39
88 #define BIASCTL 0x3d
90 const struct sound_settings_info audiohw_settings[] = {
91 [SOUND_VOLUME] = {"dB", 0, 1, -58, 6, -25},
92 [SOUND_BASS] = {"dB", 0, 1, -12, 12, 0},
93 [SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0},
94 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
95 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
96 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
97 #ifdef HAVE_RECORDING
98 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
99 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
100 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
101 #endif
102 #ifdef AUDIOHW_HAVE_BASS_CUTOFF
103 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
104 #endif
105 #ifdef AUDIOHW_HAVE_TREBLE_CUTOFF
106 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
107 #endif
110 /* shadow registers */
111 unsigned int eq1_reg;
112 unsigned int eq5_reg;
114 /* convert tenth of dB volume (-57..6) to master volume register value */
115 int tenthdb2master(int db)
117 /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */
118 /* 0111111 == +6dB (0x3f) = 63) */
119 /* 0111001 == 0dB (0x39) = 57) */
120 /* 0000001 == -56dB (0x01) = */
121 /* 0000000 == -57dB (0x00) */
123 /* 1000000 == Mute (0x40) */
125 if (db < VOLUME_MIN) {
126 return 0x40;
127 } else {
128 return((db/10)+57);
132 /* Silently enable / disable audio output */
133 void audiohw_preinit(void)
135 wmcodec_write(RESET, 0x1ff); /* Reset */
137 wmcodec_write(BIASCTL, 0x100); /* BIASCUT = 1 */
138 wmcodec_write(OUTCTRL, 0x6); /* Thermal shutdown */
140 wmcodec_write(PWRMGMT1, 0x8); /* BIASEN = 1 */
142 /* Volume zero, mute all outputs */
143 wmcodec_write(LOUT1VOL, 0x140);
144 wmcodec_write(ROUT1VOL, 0x140);
145 wmcodec_write(LOUT2VOL, 0x140);
146 wmcodec_write(ROUT2VOL, 0x140);
147 wmcodec_write(OUT3MIX, 0x40);
148 wmcodec_write(OUT4MIX, 0x40);
150 /* DAC softmute, automute, 128OSR */
151 wmcodec_write(DACCTRL, 0x4c);
153 wmcodec_write(OUT4ADC, 0x2); /* POBCTRL = 1 */
155 /* Enable output, DAC and mixer */
156 wmcodec_write(PWRMGMT3, 0x6f);
157 wmcodec_write(PWRMGMT2, 0x180);
158 wmcodec_write(PWRMGMT1, 0xd);
159 wmcodec_write(LOUTMIX, 0x1);
160 wmcodec_write(ROUTMIX, 0x1);
162 /* Disable clock since we're acting as slave to the SoC */
163 wmcodec_write(CLKGEN, 0x0);
164 wmcodec_write(AINTFCE, 0x10); /* 16-bit, I2S format */
166 wmcodec_write(LDACVOL, 0x1ff); /* Full DAC digital vol */
167 wmcodec_write(RDACVOL, 0x1ff);
169 wmcodec_write(OUT4ADC, 0x0); /* POBCTRL = 0 */
172 static void audiohw_mute(bool mute)
174 if (mute)
176 /* Set DACMU = 1 to soft-mute the audio DACs. */
177 wmcodec_write(DACCTRL, 0x4c);
178 } else {
179 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
180 wmcodec_write(DACCTRL, 0xc);
184 void audiohw_postinit(void)
186 sleep(HZ/2);
188 audiohw_mute(0);
191 void audiohw_set_headphone_vol(int vol_l, int vol_r)
193 /* OUT1 */
194 wmcodec_write(LOUT1VOL, 0x080 | vol_l);
195 wmcodec_write(ROUT1VOL, 0x180 | vol_r);
198 void audiohw_set_lineout_vol(int vol_l, int vol_r)
200 /* OUT2 */
201 wmcodec_write(LOUT2VOL, vol_l);
202 wmcodec_write(ROUT2VOL, 0x100 | vol_r);
205 void audiohw_set_aux_vol(int vol_l, int vol_r)
207 /* OUTMIX */
208 wmcodec_write(LOUTMIX, 0x111 | (vol_l << 5) );
209 wmcodec_write(ROUTMIX, 0x111 | (vol_r << 5) );
212 void audiohw_set_bass(int value)
214 eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
215 wmcodec_write(EQ1, 0x100 | eq1_reg);
218 void audiohw_set_bass_cutoff(int value)
220 eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
221 wmcodec_write(EQ1, 0x100 | eq1_reg);
224 void audiohw_set_treble(int value)
226 eq5_reg = (eq5_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
227 wmcodec_write(EQ5, eq5_reg);
230 void audiohw_set_treble_cutoff(int value)
232 eq5_reg = (eq5_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
233 wmcodec_write(EQ5, eq5_reg);
236 /* Nice shutdown of WM8985 codec */
237 void audiohw_close(void)
239 audiohw_mute(1);
241 wmcodec_write(PWRMGMT3, 0x0);
243 wmcodec_write(PWRMGMT1, 0x0);
245 wmcodec_write(PWRMGMT2, 0x40);
248 /* Note: Disable output before calling this function */
249 void audiohw_set_sample_rate(int fsel)
251 /* Currently the WM8985 acts as slave to the SoC I2S controller, so no
252 setup is needed here. This seems to be in contrast to every other WM
253 driver in Rockbox, so this may need to change in the future. */
254 (void)fsel;
257 #ifdef HAVE_RECORDING
258 void audiohw_enable_recording(bool source_mic)
260 (void)source_mic; /* We only have a line-in (I think) */
262 wmcodec_write(RESET, 0x1ff); /*Reset*/
264 wmcodec_write(PWRMGMT1, 0x2b);
265 wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
266 wmcodec_write(PWRMGMT3, 0x6f);
268 wmcodec_write(AINTFCE, 0x10);
269 wmcodec_write(CLKCTRL, 0x49);
271 wmcodec_write(OUTCTRL, 1);
273 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
274 for now */
275 audiohw_set_frequency(HW_FREQ_DEFAULT);
277 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
279 /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
280 /* 000 = disabled
281 001 = -12dB
282 010 = -9dB
283 011 = -6dB
284 100 = -3dB
285 101 = 0dB
286 110 = 3dB
287 111 = 6dB
289 wmcodec_write(LADCBOOST,0x50);
290 wmcodec_write(RADCBOOST,0x50);
292 /* Set L/R input PGA Volume to 0db */
293 // wm8758_write(LINPGAVOL,0x3f);
294 // wm8758_write(RINPGAVOL,0x13f);
296 /* Enable monitoring */
297 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
298 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
300 audiohw_mute(0);
303 void audiohw_disable_recording(void) {
304 audiohw_mute(1);
306 wmcodec_write(PWRMGMT3, 0x0);
308 wmcodec_write(PWRMGMT1, 0x0);
310 wmcodec_write(PWRMGMT2, 0x40);
313 void audiohw_set_recvol(int left, int right, int type) {
315 (void)left;
316 (void)right;
317 (void)type;
320 void audiohw_set_monitor(bool enable) {
322 (void)enable;
324 #endif /* HAVE_RECORDING */