Various minor cleanups for cowon d2
[kugel-rb.git] / firmware / drivers / audio / wm8985.c
blob06b3fa3b444c060f29fa32e8b726f00a6ea1a069
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
45 #define RDACVOL_DACVU 0x100
47 #define EQ1 0x12
48 #define EQ2 0x13
49 #define EQ3 0x14
50 #define EQ4 0x15
51 #define EQ5 0x16
52 #define EQ_GAIN_MASK 0x001f
53 #define EQ_CUTOFF_MASK 0x0060
54 #define EQ_GAIN_VALUE(x) (((-x) + 12) & 0x1f)
55 #define EQ_CUTOFF_VALUE(x) ((((x) - 1) & 0x03) << 5)
57 #define CLASSDCTL 0x17
58 #define DACLIMIT1 0x18
59 #define DACLIMIT2 0x19
60 #define NOTCH1 0x1b
61 #define NOTCH2 0x1c
62 #define NOTCH3 0x1d
63 #define NOTCH4 0x1e
64 #define ALCCTL1 0x20
65 #define ALCCTL2 0x21
66 #define ALCCTL3 0x22
67 #define NOISEGATE 0x23
68 #define PLLN 0x24
69 #define PLLK1 0x25
70 #define PLLK2 0x26
71 #define PLLK3 0x27
72 #define THREEDCTL 0x29
73 #define OUT4ADC 0x2a
74 #define BEEPCTRL 0x2b
75 #define INCTRL 0x2c
76 #define LINPGAGAIN 0x2d
77 #define RINPGAGAIN 0x2e
78 #define LADCBOOST 0x2f
79 #define RADCBOOST 0x30
80 #define OUTCTRL 0x31
81 #define LOUTMIX 0x32
82 #define ROUTMIX 0x33
83 #define LOUT1VOL 0x34
84 #define ROUT1VOL 0x35
85 #define LOUT2VOL 0x36
86 #define ROUT2VOL 0x37
87 #define OUT3MIX 0x38
88 #define OUT4MIX 0x39
89 #define BIASCTL 0x3d
91 const struct sound_settings_info audiohw_settings[] = {
92 [SOUND_VOLUME] = {"dB", 0, 1, -90, 6, -25},
93 [SOUND_BASS] = {"dB", 0, 1, -12, 12, 0},
94 [SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0},
95 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
96 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
97 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
98 #ifdef HAVE_RECORDING
99 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
100 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
101 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
102 #endif
103 #ifdef AUDIOHW_HAVE_BASS_CUTOFF
104 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
105 #endif
106 #ifdef AUDIOHW_HAVE_TREBLE_CUTOFF
107 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
108 #endif
111 /* shadow registers */
112 static unsigned int eq1_reg;
113 static unsigned int eq5_reg;
115 /* convert tenth of dB volume (-89..6) to master volume register value */
116 int tenthdb2master(int db)
118 /* Might have no sense, taken from wm8758.c :
119 att DAC AMP result
120 +6dB 0 +6 96
121 0dB 0 0 90
122 -57dB 0 -57 33
123 -58dB -1 -57 32
124 -89dB -32 -57 1
125 -90dB -oo -oo 0 */
127 if (db < VOLUME_MIN) {
128 return 0;
129 } else {
130 return (db-VOLUME_MIN)/10 + 1;
134 /* helper function coming from wm8758.c that calculates the register setting for amplifier and
135 DAC volume out of the input from tenthdb2master() */
136 static void get_volume_params(int db, int *dac, int *amp)
138 /* should never happen, set max volume for amp and dac */
139 if (db > 96) {
140 *dac = 255;
141 *amp = 63;
143 /* set dac to max and set volume for amp (better snr) */
144 else if (db > 32) {
145 *dac = 255;
146 *amp = (db-90)+57;
148 /* set amp to min and reduce dac output */
149 else if (db > 0) {
150 *dac = (db-33)*2 + 255;
151 *amp = 0;
153 /* mute all */
154 else {
155 *dac = 0x00;
156 *amp = 0x40;
160 /* Silently enable / disable audio output */
161 void audiohw_preinit(void)
163 wmcodec_write(RESET, 0x1ff); /* Reset */
165 wmcodec_write(BIASCTL, 0x100); /* BIASCUT = 1 */
166 wmcodec_write(OUTCTRL, 0x6); /* Thermal shutdown */
168 wmcodec_write(PWRMGMT1, 0x8); /* BIASEN = 1 */
170 /* Volume zero, mute all outputs */
171 wmcodec_write(LOUT1VOL, 0x140);
172 wmcodec_write(ROUT1VOL, 0x140);
173 wmcodec_write(LOUT2VOL, 0x140);
174 wmcodec_write(ROUT2VOL, 0x140);
175 wmcodec_write(OUT3MIX, 0x40);
176 wmcodec_write(OUT4MIX, 0x40);
178 /* DAC softmute, automute, 128OSR */
179 wmcodec_write(DACCTRL, 0x4c);
181 wmcodec_write(OUT4ADC, 0x2); /* POBCTRL = 1 */
183 /* Enable output, DAC and mixer */
184 wmcodec_write(PWRMGMT3, 0x6f);
185 wmcodec_write(PWRMGMT2, 0x180);
186 wmcodec_write(PWRMGMT1, 0xd);
187 wmcodec_write(LOUTMIX, 0x1);
188 wmcodec_write(ROUTMIX, 0x1);
190 /* Disable clock since we're acting as slave to the SoC */
191 wmcodec_write(CLKGEN, 0x0);
192 wmcodec_write(AINTFCE, 0x10); /* 16-bit, I2S format */
194 wmcodec_write(LDACVOL, 0x1ff); /* Full DAC digital vol */
195 wmcodec_write(RDACVOL, 0x1ff);
197 wmcodec_write(OUT4ADC, 0x0); /* POBCTRL = 0 */
200 static void audiohw_mute(bool mute)
202 if (mute)
204 /* Set DACMU = 1 to soft-mute the audio DACs. */
205 wmcodec_write(DACCTRL, 0x4c);
206 } else {
207 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
208 wmcodec_write(DACCTRL, 0xc);
212 void audiohw_postinit(void)
214 sleep(HZ/2);
216 audiohw_mute(0);
219 void audiohw_set_headphone_vol(int vol_l, int vol_r)
221 int dac_l, amp_l, dac_r, amp_r;
222 get_volume_params(vol_l, &dac_l, &amp_l);
223 get_volume_params(vol_r, &dac_r, &amp_r);
225 /* set DAC
226 Important: DAC is global and will also affect lineout */
227 wmcodec_write(LDACVOL, dac_l);
228 wmcodec_write(RDACVOL, dac_r | RDACVOL_DACVU);
230 /* set headphone amp OUT1 */
231 wmcodec_write(LOUT1VOL, amp_l | 0x080);
232 wmcodec_write(ROUT1VOL, amp_r | 0x180);
235 void audiohw_set_lineout_vol(int vol_l, int vol_r)
237 int dac_l, amp_l, dac_r, amp_r;
238 get_volume_params(vol_l, &dac_l, &amp_l);
239 get_volume_params(vol_r, &dac_r, &amp_r);
241 /* set lineout amp OUT2 */
242 wmcodec_write(LOUT2VOL, amp_l);
243 wmcodec_write(ROUT2VOL, amp_r | 0x100);
246 void audiohw_set_aux_vol(int vol_l, int vol_r)
248 /* OUTMIX */
249 wmcodec_write(LOUTMIX, 0x111 | (vol_l << 5) );
250 wmcodec_write(ROUTMIX, 0x111 | (vol_r << 5) );
253 #ifdef AUDIOHW_HAVE_BASS
254 void audiohw_set_bass(int value)
256 eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
257 wmcodec_write(EQ1, 0x100 | eq1_reg);
259 #endif /* AUDIOHW_HAVE_BASS */
261 #ifdef AUDIOHW_HAVE_BASS_CUTOFF
262 void audiohw_set_bass_cutoff(int value)
264 eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
265 wmcodec_write(EQ1, 0x100 | eq1_reg);
267 #endif /* AUDIOHW_HAVE_BASS_CUTOFF */
269 #ifdef AUDIOHW_HAVE_TREBLE
270 void audiohw_set_treble(int value)
272 eq5_reg = (eq5_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
273 wmcodec_write(EQ5, eq5_reg);
275 #endif /* AUDIOHW_HAVE_TREBLE */
277 #ifdef AUDIOHW_HAVE_TREBLE_CUTOFF
278 void audiohw_set_treble_cutoff(int value)
280 eq5_reg = (eq5_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
281 wmcodec_write(EQ5, eq5_reg);
283 #endif /* AUDIOHW_HAVE_TREBLE_CUTOFF */
285 /* Nice shutdown of WM8985 codec */
286 void audiohw_close(void)
288 audiohw_mute(1);
290 wmcodec_write(PWRMGMT3, 0x0);
292 wmcodec_write(PWRMGMT1, 0x0);
294 wmcodec_write(PWRMGMT2, 0x40);
297 #if 0 /* function is currently unused */
298 /* Note: Disable output before calling this function */
299 void audiohw_set_sample_rate(int fsel)
301 /* Currently the WM8985 acts as slave to the SoC I2S controller, so no
302 setup is needed here. This seems to be in contrast to every other WM
303 driver in Rockbox, so this may need to change in the future. */
304 (void)fsel;
306 #endif
308 #ifdef HAVE_RECORDING
309 void audiohw_enable_recording(bool source_mic)
311 (void)source_mic; /* We only have a line-in (I think) */
313 wmcodec_write(RESET, 0x1ff); /*Reset*/
315 wmcodec_write(PWRMGMT1, 0x2b);
316 wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
317 wmcodec_write(PWRMGMT3, 0x6f);
319 wmcodec_write(AINTFCE, 0x10);
320 wmcodec_write(CLKCTRL, 0x49);
322 wmcodec_write(OUTCTRL, 1);
324 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
325 for now */
326 audiohw_set_frequency(HW_FREQ_DEFAULT);
328 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
330 /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
331 /* 000 = disabled
332 001 = -12dB
333 010 = -9dB
334 011 = -6dB
335 100 = -3dB
336 101 = 0dB
337 110 = 3dB
338 111 = 6dB
340 wmcodec_write(LADCBOOST,0x50);
341 wmcodec_write(RADCBOOST,0x50);
343 /* Set L/R input PGA Volume to 0db */
344 // wm8758_write(LINPGAVOL,0x3f);
345 // wm8758_write(RINPGAVOL,0x13f);
347 /* Enable monitoring */
348 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
349 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
351 audiohw_mute(0);
354 void audiohw_disable_recording(void) {
355 audiohw_mute(1);
357 wmcodec_write(PWRMGMT3, 0x0);
359 wmcodec_write(PWRMGMT1, 0x0);
361 wmcodec_write(PWRMGMT2, 0x40);
364 void audiohw_set_recvol(int left, int right, int type) {
366 (void)left;
367 (void)right;
368 (void)type;
371 void audiohw_set_monitor(bool enable) {
373 (void)enable;
375 #endif /* HAVE_RECORDING */