blob: 9d80f9e37450f29a402d5670a07c903dbc007368 [file] [log] [blame]
Rob Purchase47ea0302008-01-14 22:04:48 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
Daniel Stenberg2acc0ac2008-06-28 18:10:04 +000010 * 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.
Rob Purchase47ea0302008-01-14 22:04:48 +000014 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include "logf.h"
20#include "system.h"
21#include "string.h"
22#include "audio.h"
23
24#include "wmcodec.h"
25#include "audiohw.h"
26#include "i2s.h"
27
Rob Purchase159f8ee2008-04-09 22:20:04 +000028/* Register addresses as per datasheet Rev.4.4 */
29#define RESET 0x00
30#define PWRMGMT1 0x01
31#define PWRMGMT2 0x02
32#define PWRMGMT3 0x03
33#define AINTFCE 0x04
34#define COMPAND 0x05
35#define CLKGEN 0x06
36#define SRATECTRL 0x07
37#define GPIOCTL 0x08
38#define JACKDETECT0 0x09
39#define DACCTRL 0x0a
40#define LDACVOL 0x0b
41#define RDACVOL 0x0c
42#define JACKDETECT1 0x0d
43#define ADCCTL 0x0e
44#define LADCVOL 0x0f
45#define RADCVOL 0x10
46
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)
56
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
90
Rob Purchase47ea0302008-01-14 22:04:48 +000091const struct sound_settings_info audiohw_settings[] = {
Rob Purchase159f8ee2008-04-09 22:20:04 +000092 [SOUND_VOLUME] = {"dB", 0, 1, -58, 6, -25},
93 [SOUND_BASS] = {"dB", 0, 1, -12, 12, 0},
94 [SOUND_TREBLE] = {"dB", 0, 1, -12, 12, 0},
Rob Purchase47ea0302008-01-14 22:04:48 +000095 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
96 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
97 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
Christian Gmeiner2ea6da12008-05-16 20:51:56 +000098#ifdef HAVE_RECORDING
Rob Purchase47ea0302008-01-14 22:04:48 +000099 [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},
Christian Gmeiner2ea6da12008-05-16 20:51:56 +0000102#endif
Rob Purchase159f8ee2008-04-09 22:20:04 +0000103 [SOUND_BASS_CUTOFF] = {"", 0, 1, 1, 4, 1},
104 [SOUND_TREBLE_CUTOFF] = {"", 0, 1, 1, 4, 1},
Rob Purchase47ea0302008-01-14 22:04:48 +0000105};
106
Rob Purchase159f8ee2008-04-09 22:20:04 +0000107/* shadow registers */
108unsigned int eq1_reg;
109unsigned int eq5_reg;
110
111/* convert tenth of dB volume (-57..6) to master volume register value */
Rob Purchase47ea0302008-01-14 22:04:48 +0000112int tenthdb2master(int db)
113{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000114 /* +6 to -57dB in 1dB steps == 64 levels = 6 bits */
115 /* 0111111 == +6dB (0x3f) = 63) */
116 /* 0111001 == 0dB (0x39) = 57) */
117 /* 0000001 == -56dB (0x01) = */
118 /* 0000000 == -57dB (0x00) */
119
120 /* 1000000 == Mute (0x40) */
121
122 if (db < VOLUME_MIN) {
123 return 0x40;
124 } else {
125 return((db/10)+57);
126 }
127}
128
Rob Purchase47ea0302008-01-14 22:04:48 +0000129/* Silently enable / disable audio output */
130void audiohw_enable_output(bool enable)
131{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000132 if (enable)
133 {
134 /* TODO: reset the I2S controller into known state */
135 //i2s_reset();
136
Rob Purchased6159ea2008-06-22 18:48:22 +0000137 wmcodec_write(RESET, 0x1ff); /* Reset */
Rob Purchase159f8ee2008-04-09 22:20:04 +0000138
Rob Purchased6159ea2008-06-22 18:48:22 +0000139 wmcodec_write(BIASCTL, 0x100); /* BIASCUT = 1 */
140 wmcodec_write(OUTCTRL, 0x6); /* Thermal shutdown */
Rob Purchase159f8ee2008-04-09 22:20:04 +0000141
Rob Purchased6159ea2008-06-22 18:48:22 +0000142 wmcodec_write(PWRMGMT1, 0x8); /* BIASEN = 1 */
143
144 /* Volume zero, mute all outputs */
145 wmcodec_write(LOUT1VOL, 0x140);
146 wmcodec_write(ROUT1VOL, 0x140);
147 wmcodec_write(LOUT2VOL, 0x140);
148 wmcodec_write(ROUT2VOL, 0x140);
149 wmcodec_write(OUT3MIX, 0x40);
150 wmcodec_write(OUT4MIX, 0x40);
151
152 /* DAC softmute, automute, 128OSR */
153 wmcodec_write(DACCTRL, 0x4c);
154
155 wmcodec_write(OUT4ADC, 0x2); /* POBCTRL = 1 */
156
157 /* Enable output, DAC and mixer */
Rob Purchase159f8ee2008-04-09 22:20:04 +0000158 wmcodec_write(PWRMGMT3, 0x6f);
Rob Purchased6159ea2008-06-22 18:48:22 +0000159 wmcodec_write(PWRMGMT2, 0x180);
160 wmcodec_write(PWRMGMT1, 0xd);
161 wmcodec_write(LOUTMIX, 0x1);
162 wmcodec_write(ROUTMIX, 0x1);
Rob Purchase159f8ee2008-04-09 22:20:04 +0000163
Rob Purchased6159ea2008-06-22 18:48:22 +0000164 /* Disable clock since we're acting as slave to the SoC */
165 wmcodec_write(CLKGEN, 0x0);
166 wmcodec_write(AINTFCE, 0x10); /* 16-bit, I2S format */
Rob Purchase159f8ee2008-04-09 22:20:04 +0000167
Rob Purchased6159ea2008-06-22 18:48:22 +0000168 wmcodec_write(LDACVOL, 0x1ff); /* Full DAC digital vol */
169 wmcodec_write(RDACVOL, 0x1ff);
Rob Purchase159f8ee2008-04-09 22:20:04 +0000170
Rob Purchased6159ea2008-06-22 18:48:22 +0000171 wmcodec_write(OUT4ADC, 0x0); /* POBCTRL = 0 */
Rob Purchase159f8ee2008-04-09 22:20:04 +0000172
Rob Purchased6159ea2008-06-22 18:48:22 +0000173 sleep(HZ/2);
174
Rob Purchase159f8ee2008-04-09 22:20:04 +0000175 audiohw_mute(0);
Rob Purchased6159ea2008-06-22 18:48:22 +0000176 }
177 else
178 {
Rob Purchase159f8ee2008-04-09 22:20:04 +0000179 audiohw_mute(1);
180 }
Rob Purchase47ea0302008-01-14 22:04:48 +0000181}
182
Rob Purchased6159ea2008-06-22 18:48:22 +0000183void audiohw_set_headphone_vol(int vol_l, int vol_r)
Rob Purchase47ea0302008-01-14 22:04:48 +0000184{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000185 /* OUT1 */
186 wmcodec_write(LOUT1VOL, 0x080 | vol_l);
187 wmcodec_write(ROUT1VOL, 0x180 | vol_r);
Rob Purchase47ea0302008-01-14 22:04:48 +0000188}
189
Christian Gmeiner06971be2008-02-13 11:19:23 +0000190void audiohw_set_lineout_vol(int vol_l, int vol_r)
Rob Purchase47ea0302008-01-14 22:04:48 +0000191{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000192 /* OUT2 */
193 wmcodec_write(LOUT2VOL, vol_l);
194 wmcodec_write(ROUT2VOL, 0x100 | vol_r);
195}
Rob Purchase47ea0302008-01-14 22:04:48 +0000196
Rob Purchase47ea0302008-01-14 22:04:48 +0000197void audiohw_set_bass(int value)
198{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000199 eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
200 wmcodec_write(EQ1, 0x100 | eq1_reg);
201}
Rob Purchase47ea0302008-01-14 22:04:48 +0000202
Rob Purchase159f8ee2008-04-09 22:20:04 +0000203void audiohw_set_bass_cutoff(int value)
204{
205 eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
206 wmcodec_write(EQ1, 0x100 | eq1_reg);
Rob Purchase47ea0302008-01-14 22:04:48 +0000207}
208
209void audiohw_set_treble(int value)
210{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000211 eq5_reg = (eq5_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
212 wmcodec_write(EQ5, eq5_reg);
213}
Rob Purchase47ea0302008-01-14 22:04:48 +0000214
Rob Purchase159f8ee2008-04-09 22:20:04 +0000215void audiohw_set_treble_cutoff(int value)
216{
217 eq5_reg = (eq5_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
218 wmcodec_write(EQ5, eq5_reg);
Rob Purchase47ea0302008-01-14 22:04:48 +0000219}
220
221void audiohw_mute(bool mute)
222{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000223 if (mute)
224 {
225 /* Set DACMU = 1 to soft-mute the audio DACs. */
Rob Purchased6159ea2008-06-22 18:48:22 +0000226 wmcodec_write(DACCTRL, 0x4c);
Rob Purchase159f8ee2008-04-09 22:20:04 +0000227 } else {
228 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
Rob Purchased6159ea2008-06-22 18:48:22 +0000229 wmcodec_write(DACCTRL, 0xc);
Rob Purchase159f8ee2008-04-09 22:20:04 +0000230 }
Rob Purchase47ea0302008-01-14 22:04:48 +0000231}
232
Rob Purchased6159ea2008-06-22 18:48:22 +0000233/* Nice shutdown of WM8985 codec */
Rob Purchase47ea0302008-01-14 22:04:48 +0000234void audiohw_close(void)
235{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000236 audiohw_mute(1);
237
238 wmcodec_write(PWRMGMT3, 0x0);
239
240 wmcodec_write(PWRMGMT1, 0x0);
241
242 wmcodec_write(PWRMGMT2, 0x40);
Rob Purchase47ea0302008-01-14 22:04:48 +0000243}
244
Rob Purchase47ea0302008-01-14 22:04:48 +0000245/* Note: Disable output before calling this function */
246void audiohw_set_sample_rate(int sampling_control)
247{
Rob Purchased6159ea2008-06-22 18:48:22 +0000248 /* Currently the WM8985 acts as slave to the SoC I2S controller, so no
249 setup is needed here. This seems to be in contrast to every other WM
250 driver in Rockbox, so this may need to change in the future. */
Rob Purchase47ea0302008-01-14 22:04:48 +0000251 (void)sampling_control;
252}
253
Bertrik Sikken6a0340f2008-05-03 23:18:56 +0000254#ifdef HAVE_RECORDING
Rob Purchase47ea0302008-01-14 22:04:48 +0000255void audiohw_enable_recording(bool source_mic)
256{
Rob Purchase159f8ee2008-04-09 22:20:04 +0000257 (void)source_mic; /* We only have a line-in (I think) */
Rob Purchase47ea0302008-01-14 22:04:48 +0000258
Rob Purchase159f8ee2008-04-09 22:20:04 +0000259 /* TODO: reset the I2S controller into known state */
260 //i2s_reset();
261
262 wmcodec_write(RESET, 0x1ff); /*Reset*/
263
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);
267
268 wmcodec_write(AINTFCE, 0x10);
269 wmcodec_write(CLKCTRL, 0x49);
270
271 wmcodec_write(OUTCTRL, 1);
272
273 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
274 for now */
275 audiohw_set_sample_rate(WM8985_44100HZ);
276
277 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
278
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
288 */
289 wmcodec_write(LADCBOOST,0x50);
290 wmcodec_write(RADCBOOST,0x50);
291
292 /* Set L/R input PGA Volume to 0db */
293 // wm8758_write(LINPGAVOL,0x3f);
294 // wm8758_write(RINPGAVOL,0x13f);
295
296 /* Enable monitoring */
297 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
298 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
299
300 audiohw_mute(0);
Rob Purchase47ea0302008-01-14 22:04:48 +0000301}
302
Rob Purchase159f8ee2008-04-09 22:20:04 +0000303void audiohw_disable_recording(void) {
304 audiohw_mute(1);
305
306 wmcodec_write(PWRMGMT3, 0x0);
307
308 wmcodec_write(PWRMGMT1, 0x0);
309
310 wmcodec_write(PWRMGMT2, 0x40);
311}
312
313void audiohw_set_recvol(int left, int right, int type) {
Rob Purchase47ea0302008-01-14 22:04:48 +0000314
315 (void)left;
316 (void)right;
317 (void)type;
318}
319
Rob Purchase159f8ee2008-04-09 22:20:04 +0000320void audiohw_set_monitor(bool enable) {
Rob Purchase47ea0302008-01-14 22:04:48 +0000321
322 (void)enable;
323}
Bertrik Sikken6a0340f2008-05-03 23:18:56 +0000324#endif /* HAVE_RECORDING */