always call the class driver init function. This is needed because they are called...
[kugel-rb.git] / firmware / drivers / audio / wm8985.c
blobd59d2d3230df2ee8b56367484f765621cf661fe5
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 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
103 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
106 /* shadow registers */
107 unsigned int eq1_reg;
108 unsigned int eq5_reg;
110 /* convert tenth of dB volume (-57..6) to master volume register value */
111 int tenthdb2master(int db)
113 /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */
114 /* 0111111 == +6dB (0x3f) = 63) */
115 /* 0111001 == 0dB (0x39) = 57) */
116 /* 0000001 == -56dB (0x01) = */
117 /* 0000000 == -57dB (0x00) */
119 /* 1000000 == Mute (0x40) */
121 if (db < VOLUME_MIN) {
122 return 0x40;
123 } else {
124 return((db/10)+57);
128 /* Silently enable / disable audio output */
129 void audiohw_preinit(void)
131 wmcodec_write(RESET, 0x1ff); /* Reset */
133 wmcodec_write(BIASCTL, 0x100); /* BIASCUT = 1 */
134 wmcodec_write(OUTCTRL, 0x6); /* Thermal shutdown */
136 wmcodec_write(PWRMGMT1, 0x8); /* BIASEN = 1 */
138 /* Volume zero, mute all outputs */
139 wmcodec_write(LOUT1VOL, 0x140);
140 wmcodec_write(ROUT1VOL, 0x140);
141 wmcodec_write(LOUT2VOL, 0x140);
142 wmcodec_write(ROUT2VOL, 0x140);
143 wmcodec_write(OUT3MIX, 0x40);
144 wmcodec_write(OUT4MIX, 0x40);
146 /* DAC softmute, automute, 128OSR */
147 wmcodec_write(DACCTRL, 0x4c);
149 wmcodec_write(OUT4ADC, 0x2); /* POBCTRL = 1 */
151 /* Enable output, DAC and mixer */
152 wmcodec_write(PWRMGMT3, 0x6f);
153 wmcodec_write(PWRMGMT2, 0x180);
154 wmcodec_write(PWRMGMT1, 0xd);
155 wmcodec_write(LOUTMIX, 0x1);
156 wmcodec_write(ROUTMIX, 0x1);
158 /* Disable clock since we're acting as slave to the SoC */
159 wmcodec_write(CLKGEN, 0x0);
160 wmcodec_write(AINTFCE, 0x10); /* 16-bit, I2S format */
162 wmcodec_write(LDACVOL, 0x1ff); /* Full DAC digital vol */
163 wmcodec_write(RDACVOL, 0x1ff);
165 wmcodec_write(OUT4ADC, 0x0); /* POBCTRL = 0 */
168 void audiohw_postinit(void)
170 sleep(HZ/2);
172 audiohw_mute(0);
175 void audiohw_set_headphone_vol(int vol_l, int vol_r)
177 /* OUT1 */
178 wmcodec_write(LOUT1VOL, 0x080 | vol_l);
179 wmcodec_write(ROUT1VOL, 0x180 | vol_r);
182 void audiohw_set_lineout_vol(int vol_l, int vol_r)
184 /* OUT2 */
185 wmcodec_write(LOUT2VOL, vol_l);
186 wmcodec_write(ROUT2VOL, 0x100 | vol_r);
189 void audiohw_set_aux_vol(int vol_l, int vol_r)
191 /* OUTMIX */
192 wmcodec_write(LOUTMIX, 0x111 | (vol_l << 5) );
193 wmcodec_write(ROUTMIX, 0x111 | (vol_r << 5) );
196 void audiohw_set_bass(int value)
198 eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
199 wmcodec_write(EQ1, 0x100 | eq1_reg);
202 void audiohw_set_bass_cutoff(int value)
204 eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
205 wmcodec_write(EQ1, 0x100 | eq1_reg);
208 void audiohw_set_treble(int value)
210 eq5_reg = (eq5_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
211 wmcodec_write(EQ5, eq5_reg);
214 void audiohw_set_treble_cutoff(int value)
216 eq5_reg = (eq5_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
217 wmcodec_write(EQ5, eq5_reg);
220 void audiohw_mute(bool mute)
222 if (mute)
224 /* Set DACMU = 1 to soft-mute the audio DACs. */
225 wmcodec_write(DACCTRL, 0x4c);
226 } else {
227 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
228 wmcodec_write(DACCTRL, 0xc);
232 /* Nice shutdown of WM8985 codec */
233 void audiohw_close(void)
235 audiohw_mute(1);
237 wmcodec_write(PWRMGMT3, 0x0);
239 wmcodec_write(PWRMGMT1, 0x0);
241 wmcodec_write(PWRMGMT2, 0x40);
244 /* Note: Disable output before calling this function */
245 void audiohw_set_sample_rate(int fsel)
247 /* Currently the WM8985 acts as slave to the SoC I2S controller, so no
248 setup is needed here. This seems to be in contrast to every other WM
249 driver in Rockbox, so this may need to change in the future. */
250 (void)fsel;
253 #ifdef HAVE_RECORDING
254 void audiohw_enable_recording(bool source_mic)
256 (void)source_mic; /* We only have a line-in (I think) */
258 wmcodec_write(RESET, 0x1ff); /*Reset*/
260 wmcodec_write(PWRMGMT1, 0x2b);
261 wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
262 wmcodec_write(PWRMGMT3, 0x6f);
264 wmcodec_write(AINTFCE, 0x10);
265 wmcodec_write(CLKCTRL, 0x49);
267 wmcodec_write(OUTCTRL, 1);
269 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
270 for now */
271 audiohw_set_frequency(HW_FREQ_DEFAULT);
273 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
275 /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
276 /* 000 = disabled
277 001 = -12dB
278 010 = -9dB
279 011 = -6dB
280 100 = -3dB
281 101 = 0dB
282 110 = 3dB
283 111 = 6dB
285 wmcodec_write(LADCBOOST,0x50);
286 wmcodec_write(RADCBOOST,0x50);
288 /* Set L/R input PGA Volume to 0db */
289 // wm8758_write(LINPGAVOL,0x3f);
290 // wm8758_write(RINPGAVOL,0x13f);
292 /* Enable monitoring */
293 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
294 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
296 audiohw_mute(0);
299 void audiohw_disable_recording(void) {
300 audiohw_mute(1);
302 wmcodec_write(PWRMGMT3, 0x0);
304 wmcodec_write(PWRMGMT1, 0x0);
306 wmcodec_write(PWRMGMT2, 0x40);
309 void audiohw_set_recvol(int left, int right, int type) {
311 (void)left;
312 (void)right;
313 (void)type;
316 void audiohw_set_monitor(bool enable) {
318 (void)enable;
320 #endif /* HAVE_RECORDING */