FS#11417 by Joe Balough: fix audio/tuner on philips hdd6330
[kugel-rb.git] / firmware / drivers / audio / wm8985.c
bloba76e20e57bca580c68838b007fb832d2a2abd05a
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 unsigned int eq1_reg;
113 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 void audiohw_set_bass(int value)
255 eq1_reg = (eq1_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
256 wmcodec_write(EQ1, 0x100 | eq1_reg);
259 void audiohw_set_bass_cutoff(int value)
261 eq1_reg = (eq1_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
262 wmcodec_write(EQ1, 0x100 | eq1_reg);
265 void audiohw_set_treble(int value)
267 eq5_reg = (eq5_reg & ~EQ_GAIN_MASK) | EQ_GAIN_VALUE(value);
268 wmcodec_write(EQ5, eq5_reg);
271 void audiohw_set_treble_cutoff(int value)
273 eq5_reg = (eq5_reg & ~EQ_CUTOFF_MASK) | EQ_CUTOFF_VALUE(value);
274 wmcodec_write(EQ5, eq5_reg);
277 /* Nice shutdown of WM8985 codec */
278 void audiohw_close(void)
280 audiohw_mute(1);
282 wmcodec_write(PWRMGMT3, 0x0);
284 wmcodec_write(PWRMGMT1, 0x0);
286 wmcodec_write(PWRMGMT2, 0x40);
289 /* Note: Disable output before calling this function */
290 void audiohw_set_sample_rate(int fsel)
292 /* Currently the WM8985 acts as slave to the SoC I2S controller, so no
293 setup is needed here. This seems to be in contrast to every other WM
294 driver in Rockbox, so this may need to change in the future. */
295 (void)fsel;
298 #ifdef HAVE_RECORDING
299 void audiohw_enable_recording(bool source_mic)
301 (void)source_mic; /* We only have a line-in (I think) */
303 wmcodec_write(RESET, 0x1ff); /*Reset*/
305 wmcodec_write(PWRMGMT1, 0x2b);
306 wmcodec_write(PWRMGMT2, 0x18f); /* Enable ADC - 0x0c enables left/right PGA input, and 0x03 turns on power to the ADCs */
307 wmcodec_write(PWRMGMT3, 0x6f);
309 wmcodec_write(AINTFCE, 0x10);
310 wmcodec_write(CLKCTRL, 0x49);
312 wmcodec_write(OUTCTRL, 1);
314 /* The iPod can handle multiple frequencies, but fix at 44.1KHz
315 for now */
316 audiohw_set_frequency(HW_FREQ_DEFAULT);
318 wmcodec_write(INCTRL,0x44); /* Connect L2 and R2 inputs */
320 /* Set L2/R2_2BOOSTVOL to 0db (bits 4-6) */
321 /* 000 = disabled
322 001 = -12dB
323 010 = -9dB
324 011 = -6dB
325 100 = -3dB
326 101 = 0dB
327 110 = 3dB
328 111 = 6dB
330 wmcodec_write(LADCBOOST,0x50);
331 wmcodec_write(RADCBOOST,0x50);
333 /* Set L/R input PGA Volume to 0db */
334 // wm8758_write(LINPGAVOL,0x3f);
335 // wm8758_write(RINPGAVOL,0x13f);
337 /* Enable monitoring */
338 wmcodec_write(LOUTMIX,0x17); /* Enable output mixer - BYPL2LMIX @ 0db*/
339 wmcodec_write(ROUTMIX,0x17); /* Enable output mixer - BYPR2RMIX @ 0db*/
341 audiohw_mute(0);
344 void audiohw_disable_recording(void) {
345 audiohw_mute(1);
347 wmcodec_write(PWRMGMT3, 0x0);
349 wmcodec_write(PWRMGMT1, 0x0);
351 wmcodec_write(PWRMGMT2, 0x40);
354 void audiohw_set_recvol(int left, int right, int type) {
356 (void)left;
357 (void)right;
358 (void)type;
361 void audiohw_set_monitor(bool enable) {
363 (void)enable;
365 #endif /* HAVE_RECORDING */