Initial D2 sound playback support (known issues to follow on the CowonD2Info wiki...
[kugel-rb.git] / firmware / drivers / audio / wm8985.c
blob411bd97c5999cea7a24bd019af92047b2c7f5650
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * All files in this archive are subject to the GNU General Public License.
11 * See the file COPYING in the source tree root for full license agreement.
13 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
14 * KIND, either express or implied.
16 ****************************************************************************/
17 #include "logf.h"
18 #include "system.h"
19 #include "string.h"
20 #include "audio.h"
22 #include "wmcodec.h"
23 #include "audiohw.h"
24 #include "i2s.h"
26 /* Register addresses as per datasheet Rev.4.4 */
27 #define RESET 0x00
28 #define PWRMGMT1 0x01
29 #define PWRMGMT2 0x02
30 #define PWRMGMT3 0x03
31 #define AINTFCE 0x04
32 #define COMPAND 0x05
33 #define CLKGEN 0x06
34 #define SRATECTRL 0x07
35 #define GPIOCTL 0x08
36 #define JACKDETECT0 0x09
37 #define DACCTRL 0x0a
38 #define LDACVOL 0x0b
39 #define RDACVOL 0x0c
40 #define JACKDETECT1 0x0d
41 #define ADCCTL 0x0e
42 #define LADCVOL 0x0f
43 #define RADCVOL 0x10
45 #define EQ1 0x12
46 #define EQ2 0x13
47 #define EQ3 0x14
48 #define EQ4 0x15
49 #define EQ5 0x16
50 #define EQ_GAIN_MASK 0x001f
51 #define EQ_CUTOFF_MASK 0x0060
52 #define EQ_GAIN_VALUE(x) (((-x) + 12) & 0x1f)
53 #define EQ_CUTOFF_VALUE(x) ((((x) - 1) & 0x03) << 5)
55 #define CLASSDCTL 0x17
56 #define DACLIMIT1 0x18
57 #define DACLIMIT2 0x19
58 #define NOTCH1 0x1b
59 #define NOTCH2 0x1c
60 #define NOTCH3 0x1d
61 #define NOTCH4 0x1e
62 #define ALCCTL1 0x20
63 #define ALCCTL2 0x21
64 #define ALCCTL3 0x22
65 #define NOISEGATE 0x23
66 #define PLLN 0x24
67 #define PLLK1 0x25
68 #define PLLK2 0x26
69 #define PLLK3 0x27
70 #define THREEDCTL 0x29
71 #define OUT4ADC 0x2a
72 #define BEEPCTRL 0x2b
73 #define INCTRL 0x2c
74 #define LINPGAGAIN 0x2d
75 #define RINPGAGAIN 0x2e
76 #define LADCBOOST 0x2f
77 #define RADCBOOST 0x30
78 #define OUTCTRL 0x31
79 #define LOUTMIX 0x32
80 #define ROUTMIX 0x33
81 #define LOUT1VOL 0x34
82 #define ROUT1VOL 0x35
83 #define LOUT2VOL 0x36
84 #define ROUT2VOL 0x37
85 #define OUT3MIX 0x38
86 #define OUT4MIX 0x39
87 #define BIASCTL 0x3d
89 const struct sound_settings_info audiohw_settings[] = {
90 [SOUND_VOLUME] = {"dB", 0, 1, -58, 6, -25},
91 [SOUND_BASS] = {"dB", 0, 1, -12, 12, 0},
92 [SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0},
93 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
94 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
95 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
96 #ifdef HAVE_RECORDING
97 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0},
98 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0},
99 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16},
100 #endif
101 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
102 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
105 /* shadow registers */
106 unsigned int eq1_reg;
107 unsigned int eq5_reg;
109 /* convert tenth of dB volume (-57..6) to master volume register value */
110 int tenthdb2master(int db)
112 /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */
113 /* 0111111 == +6dB (0x3f) = 63) */
114 /* 0111001 == 0dB (0x39) = 57) */
115 /* 0000001 == -56dB (0x01) = */
116 /* 0000000 == -57dB (0x00) */
118 /* 1000000 == Mute (0x40) */
120 if (db < VOLUME_MIN) {
121 return 0x40;
122 } else {
123 return((db/10)+57);
127 /* Silently enable / disable audio output */
128 void audiohw_enable_output(bool enable)
130 if (enable)
132 /* TODO: reset the I2S controller into known state */
133 //i2s_reset();
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 */
171 sleep(HZ/2);
173 audiohw_mute(0);
175 else
177 audiohw_mute(1);
181 void audiohw_set_headphone_vol(int vol_l, int vol_r)
183 /* OUT1 */
184 wmcodec_write(LOUT1VOL, 0x080 | vol_l);
185 wmcodec_write(ROUT1VOL, 0x180 | vol_r);
188 void audiohw_set_lineout_vol(int vol_l, int vol_r)
190 /* OUT2 */
191 wmcodec_write(LOUT2VOL, vol_l);
192 wmcodec_write(ROUT2VOL, 0x100 | vol_r);
195 void audiohw_set_bass(int value)
197 eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
198 wmcodec_write(EQ1, 0x100 | eq1_reg);
201 void audiohw_set_bass_cutoff(int value)
203 eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
204 wmcodec_write(EQ1, 0x100 | eq1_reg);
207 void audiohw_set_treble(int value)
209 eq5_reg = (eq5_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
210 wmcodec_write(EQ5, eq5_reg);
213 void audiohw_set_treble_cutoff(int value)
215 eq5_reg = (eq5_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
216 wmcodec_write(EQ5, eq5_reg);
219 void audiohw_mute(bool mute)
221 if (mute)
223 /* Set DACMU = 1 to soft-mute the audio DACs. */
224 wmcodec_write(DACCTRL, 0x4c);
225 } else {
226 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
227 wmcodec_write(DACCTRL, 0xc);
231 /* Nice shutdown of WM8985 codec */
232 void audiohw_close(void)
234 audiohw_mute(1);
236 wmcodec_write(PWRMGMT3, 0x0);
238 wmcodec_write(PWRMGMT1, 0x0);
240 wmcodec_write(PWRMGMT2, 0x40);
243 /* Note: Disable output before calling this function */
244 void audiohw_set_sample_rate(int sampling_control)
246 /* Currently the WM8985 acts as slave to the SoC I2S controller, so no
247 setup is needed here. This seems to be in contrast to every other WM
248 driver in Rockbox, so this may need to change in the future. */
249 (void)sampling_control;
252 #ifdef HAVE_RECORDING
253 void audiohw_enable_recording(bool source_mic)
255 (void)source_mic; /* We only have a line-in (I think) */
257 /* TODO: reset the I2S controller into known state */
258 //i2s_reset();
260 wmcodec_write(RESET, 0x1ff); /*Reset*/
262 wmcodec_write(PWRMGMT1, 0x2b);
263 wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
264 wmcodec_write(PWRMGMT3, 0x6f);
266 wmcodec_write(AINTFCE, 0x10);
267 wmcodec_write(CLKCTRL, 0x49);
269 wmcodec_write(OUTCTRL, 1);
271 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
272 for now */
273 audiohw_set_sample_rate(WM8985_44100HZ);
275 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
277 /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
278 /* 000 = disabled
279 001 = -12dB
280 010 = -9dB
281 011 = -6dB
282 100 = -3dB
283 101 = 0dB
284 110 = 3dB
285 111 = 6dB
287 wmcodec_write(LADCBOOST,0x50);
288 wmcodec_write(RADCBOOST,0x50);
290 /* Set L/R input PGA Volume to 0db */
291 // wm8758_write(LINPGAVOL,0x3f);
292 // wm8758_write(RINPGAVOL,0x13f);
294 /* Enable monitoring */
295 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
296 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
298 audiohw_mute(0);
301 void audiohw_disable_recording(void) {
302 audiohw_mute(1);
304 wmcodec_write(PWRMGMT3, 0x0);
306 wmcodec_write(PWRMGMT1, 0x0);
308 wmcodec_write(PWRMGMT2, 0x40);
311 void audiohw_set_recvol(int left, int right, int type) {
313 (void)left;
314 (void)right;
315 (void)type;
318 void audiohw_set_monitor(bool enable) {
320 (void)enable;
322 #endif /* HAVE_RECORDING */