WM8978: sound.c weirdness strikes again. Prescaler values have to be in centibels.
[kugel-rb.git] / firmware / drivers / audio / wm8978.c
blobf83a832854422627421a309777a9979f70711362
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2008 by Michael Sevakis
12 * Driver for WM8978 audio codec
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
22 ****************************************************************************/
23 #include "config.h"
24 #include "system.h"
25 #include "audiohw.h"
26 #include "wmcodec.h"
27 #include "audio.h"
28 /*#define LOGF_ENABLE*/
29 #include "logf.h"
31 /* TODO: Define/refine an API for special hardware steps outside the
32 * main codec driver such as special GPIO handling. */
33 /* NOTE: Much of the volume code is very interdependent and calibrated for
34 * the Gigabeat S. If you change anything for another device that uses this
35 * file it may break things. */
36 extern void audiohw_enable_headphone_jack(bool enable);
38 const struct sound_settings_info audiohw_settings[] =
40 [SOUND_VOLUME] = {"dB", 0, 1, -90, 6, -25},
41 [SOUND_BALANCE] = {"%", 0, 1,-100, 100, 0},
42 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
43 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
44 [SOUND_EQ_BAND1_GAIN] = {"dB", 0, 1, -12, 12, 0},
45 [SOUND_EQ_BAND2_GAIN] = {"dB", 0, 1, -12, 12, 0},
46 [SOUND_EQ_BAND3_GAIN] = {"dB", 0, 1, -12, 12, 0},
47 [SOUND_EQ_BAND4_GAIN] = {"dB", 0, 1, -12, 12, 0},
48 [SOUND_EQ_BAND5_GAIN] = {"dB", 0, 1, -12, 12, 0},
49 [SOUND_EQ_BAND1_FREQUENCY] = {"", 0, 1, 0, 3, 0},
50 [SOUND_EQ_BAND2_FREQUENCY] = {"", 0, 1, 0, 3, 0},
51 [SOUND_EQ_BAND3_FREQUENCY] = {"", 0, 1, 0, 3, 0},
52 [SOUND_EQ_BAND4_FREQUENCY] = {"", 0, 1, 0, 3, 0},
53 [SOUND_EQ_BAND5_FREQUENCY] = {"", 0, 1, 0, 3, 0},
54 [SOUND_EQ_BAND2_WIDTH] = {"", 0, 1, 0, 1, 0},
55 [SOUND_EQ_BAND3_WIDTH] = {"", 0, 1, 0, 1, 0},
56 [SOUND_EQ_BAND4_WIDTH] = {"", 0, 1, 0, 1, 0},
57 [SOUND_DEPTH_3D] = {"%", 0, 1, 0, 15, 0},
58 #ifdef HAVE_RECORDING
59 /* Digital: -119.0dB to +8.0dB in 0.5dB increments
60 * Analog: Relegated to volume control
61 * Circumstances unfortunately do not allow a great deal of positive
62 * gain. */
63 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-238, 16, 0},
64 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-238, 16, 0},
65 #if 0
66 [SOUND_MIC_GAIN] = {"dB", 1, 1,-238, 16, 0},
67 #endif
68 #endif
71 static uint16_t wmc_regs[WMC_NUM_REGISTERS] =
73 /* Initialized with post-reset default values - the 2-wire interface
74 * cannot be read. Or-in additional bits desired for some registers. */
75 [0 ... WMC_NUM_REGISTERS-1] = 0x8000, /* To ID invalids in gaps */
76 [WMC_SOFTWARE_RESET] = 0x000,
77 [WMC_POWER_MANAGEMENT1] = 0x000,
78 [WMC_POWER_MANAGEMENT2] = 0x000,
79 [WMC_POWER_MANAGEMENT3] = 0x000,
80 [WMC_AUDIO_INTERFACE] = 0x050,
81 [WMC_COMPANDING_CTRL] = 0x000,
82 [WMC_CLOCK_GEN_CTRL] = 0x140,
83 [WMC_ADDITIONAL_CTRL] = 0x000,
84 [WMC_GPIO] = 0x000,
85 [WMC_JACK_DETECT_CONTROL1] = 0x000,
86 [WMC_DAC_CONTROL] = 0x000,
87 [WMC_LEFT_DAC_DIGITAL_VOL] = 0x0ff, /* Latch left first */
88 [WMC_RIGHT_DAC_DIGITAL_VOL] = 0x0ff | WMC_VU,
89 [WMC_JACK_DETECT_CONTROL2] = 0x000,
90 [WMC_ADC_CONTROL] = 0x100,
91 [WMC_LEFT_ADC_DIGITAL_VOL] = 0x0ff, /* Latch left first */
92 [WMC_RIGHT_ADC_DIGITAL_VOL] = 0x0ff | WMC_VU,
93 [WMC_EQ1_LOW_SHELF] = 0x12c,
94 [WMC_EQ2_PEAK1] = 0x02c,
95 [WMC_EQ3_PEAK2] = 0x02c,
96 [WMC_EQ4_PEAK3] = 0x02c,
97 [WMC_EQ5_HIGH_SHELF] = 0x02c,
98 [WMC_DAC_LIMITER1] = 0x032,
99 [WMC_DAC_LIMITER2] = 0x000,
100 [WMC_NOTCH_FILTER1] = 0x000,
101 [WMC_NOTCH_FILTER2] = 0x000,
102 [WMC_NOTCH_FILTER3] = 0x000,
103 [WMC_NOTCH_FILTER4] = 0x000,
104 [WMC_ALC_CONTROL1] = 0x038,
105 [WMC_ALC_CONTROL2] = 0x00b,
106 [WMC_ALC_CONTROL3] = 0x032,
107 [WMC_NOISE_GATE] = 0x000,
108 [WMC_PLL_N] = 0x008,
109 [WMC_PLL_K1] = 0x00c,
110 [WMC_PLL_K2] = 0x093,
111 [WMC_PLL_K3] = 0x0e9,
112 [WMC_3D_CONTROL] = 0x000,
113 [WMC_BEEP_CONTROL] = 0x000,
114 [WMC_INPUT_CTRL] = 0x033,
115 [WMC_LEFT_INP_PGA_GAIN_CTRL] = 0x010 | WMC_ZC, /* Latch left first */
116 [WMC_RIGHT_INP_PGA_GAIN_CTRL] = 0x010 | WMC_VU | WMC_ZC,
117 [WMC_LEFT_ADC_BOOST_CTRL] = 0x100,
118 [WMC_RIGHT_ADC_BOOST_CTRL] = 0x100,
119 [WMC_OUTPUT_CTRL] = 0x002,
120 [WMC_LEFT_MIXER_CTRL] = 0x001,
121 [WMC_RIGHT_MIXER_CTRL] = 0x001,
122 [WMC_LOUT1_HP_VOLUME_CTRL] = 0x039 | WMC_ZC, /* Latch left first */
123 [WMC_ROUT1_HP_VOLUME_CTRL] = 0x039 | WMC_VU | WMC_ZC,
124 [WMC_LOUT2_SPK_VOLUME_CTRL] = 0x039 | WMC_ZC, /* Latch left first */
125 [WMC_ROUT2_SPK_VOLUME_CTRL] = 0x039 | WMC_VU | WMC_ZC,
126 [WMC_OUT3_MIXER_CTRL] = 0x001,
127 [WMC_OUT4_MONO_MIXER_CTRL] = 0x001,
130 struct
132 signed char vol_l;
133 signed char vol_r;
134 unsigned char dac_l;
135 unsigned char dac_r;
136 unsigned char ahw_mute;
137 unsigned char prescaler; /* Attenuation */
138 unsigned char eq_on; /* Enabled */
139 signed char band_gain[5]; /* Setting */
140 unsigned char enh_3d_prescaler; /* Attenuation */
141 unsigned char enh_3d_on; /* Enabled */
142 unsigned char enh_3d; /* Setting */
143 } wmc_vol =
145 .vol_l = 0,
146 .vol_r = 0,
147 .dac_l = 0,
148 .dac_r = 0,
149 .ahw_mute = false,
150 .prescaler = 0,
151 .eq_on = true,
152 .band_gain = { 0, 0, 0, 0, 0 },
153 .enh_3d_prescaler = 0,
154 .enh_3d_on = true,
155 .enh_3d = 0,
158 static void wmc_write(unsigned int reg, unsigned int val)
160 if (reg >= WMC_NUM_REGISTERS || (wmc_regs[reg] & 0x8000))
162 logf("wm8978 invalid register: %d", reg);
163 return;
166 wmc_regs[reg] = val & ~0x8000;
167 wmcodec_write(reg, val);
170 void wmc_set(unsigned int reg, unsigned int bits)
172 wmc_write(reg, wmc_regs[reg] | bits);
175 void wmc_clear(unsigned int reg, unsigned int bits)
177 wmc_write(reg, wmc_regs[reg] & ~bits);
180 static void wmc_write_masked(unsigned int reg, unsigned int bits,
181 unsigned int mask)
183 wmc_write(reg, (wmc_regs[reg] & ~mask) | (bits & mask));
186 /* convert tenth of dB volume (-890..60) to master volume register value
187 * (000000...111111) */
188 int tenthdb2master(int db)
190 /* -90dB to +6dB 1dB steps (96 levels) 7bits */
191 /* 1100000 == +6dB (0x60,96) */
192 /* 1101010 == 0dB (0x5a,90) */
193 /* 1000001 == -57dB (0x21,33,DAC) */
194 /* 0000001 == -89dB (0x01,01) */
195 /* 0000000 == -90dB (0x00,00,Mute) */
196 if (db <= VOLUME_MIN)
198 return 0x0;
200 else
202 return (db - VOLUME_MIN) / 10;
206 int sound_val2phys(int setting, int value)
208 int result;
210 switch (setting)
212 #ifdef HAVE_RECORDING
213 case SOUND_LEFT_GAIN:
214 case SOUND_RIGHT_GAIN:
215 case SOUND_MIC_GAIN:
216 result = value * 5;
217 break;
218 #endif
220 case SOUND_EQ_BAND1_GAIN+0x10000:
221 case SOUND_EQ_BAND2_GAIN+0x10000:
222 case SOUND_EQ_BAND3_GAIN+0x10000:
223 case SOUND_EQ_BAND4_GAIN+0x10000:
224 case SOUND_EQ_BAND5_GAIN+0x10000:
225 result = value * 10;
226 break;
228 case SOUND_DEPTH_3D:
229 result = (100 * value + 8) / 15;
230 break;
232 default:
233 result = value;
236 return result;
239 void audiohw_preinit(void)
241 /* 1. Turn on external power supplies. Wait for supply voltage to settle. */
243 /* Step 1 should be completed already. Reset and return all registers to
244 * defaults */
245 wmcodec_write(WMC_SOFTWARE_RESET, 0xff);
246 sleep(HZ/10);
248 /* 2. Mute all analogue outputs */
249 wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
250 wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
251 wmc_set(WMC_LOUT2_SPK_VOLUME_CTRL, WMC_MUTE);
252 wmc_set(WMC_ROUT2_SPK_VOLUME_CTRL, WMC_MUTE);
253 wmc_set(WMC_OUT3_MIXER_CTRL, WMC_MUTE);
254 wmc_set(WMC_OUT4_MONO_MIXER_CTRL, WMC_MUTE);
256 /* 3. Set L/RMIXEN = 1 and DACENL/R = 1 in register R3. */
257 wmc_write(WMC_POWER_MANAGEMENT3, WMC_RMIXEN | WMC_LMIXEN);
259 /* EQ and 3D applied to DAC (Set before DAC enable!) */
260 wmc_set(WMC_EQ1_LOW_SHELF, WMC_EQ3DMODE);
262 wmc_set(WMC_POWER_MANAGEMENT3, WMC_DACENR | WMC_DACENL);
264 /* 4. Set BUFIOEN = 1 and VMIDSEL[1:0] to required value in register
265 * R1. Wait for VMID supply to settle */
266 wmc_write(WMC_POWER_MANAGEMENT1, WMC_BUFIOEN | WMC_VMIDSEL_300K);
267 sleep(HZ/10);
269 /* 5. Set BIASEN = 1 in register R1. */
270 wmc_set(WMC_POWER_MANAGEMENT1, WMC_BIASEN);
272 /* 6. Set L/ROUTEN = 1 in register R2. */
273 wmc_write(WMC_POWER_MANAGEMENT2, WMC_LOUT1EN | WMC_ROUT1EN);
276 void audiohw_postinit(void)
278 sleep(5*HZ/4);
280 /* 7. Enable other mixers as required */
282 /* 8. Enable other outputs as required */
284 /* 9. Set remaining registers */
285 wmc_write(WMC_AUDIO_INTERFACE, WMC_WL_16 | WMC_FMT_I2S);
286 wmc_write(WMC_DAC_CONTROL, WMC_DACOSR_128 | WMC_AMUTE);
288 /* No ADC, no HP filter, no popping */
289 wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN);
291 wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
292 wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
294 /* Specific to HW clocking */
295 wmc_write_masked(WMC_CLOCK_GEN_CTRL, WMC_BCLKDIV_4 | WMC_MS,
296 WMC_BCLKDIV | WMC_MS | WMC_CLKSEL);
297 audiohw_set_frequency(HW_FREQ_DEFAULT);
299 audiohw_enable_headphone_jack(true);
302 static void get_headphone_levels(int val, int *dac_p, int *hp_p,
303 int *mix_p, int *boost_p)
305 int dac, hp, mix, boost;
307 if (val >= 33)
309 dac = 255;
310 hp = val - 33;
311 mix = 7;
312 boost = 5;
314 else if (val >= 21)
316 dac = 189 + val / 3 * 6;
317 hp = val % 3;
318 mix = 7;
319 boost = (val - 18) / 3;
321 else
323 dac = 189 + val / 3 * 6;
324 hp = val % 3;
325 mix = val / 3;
326 boost = 1;
329 *dac_p = dac;
330 *hp_p = hp;
331 *mix_p = mix;
332 *boost_p = boost;
335 static void sync_prescaler(void)
337 int prescaler = 0;
339 /* Combine all prescaling into a single DAC attenuation */
340 if (wmc_vol.eq_on)
341 prescaler = wmc_vol.prescaler;
343 if (wmc_vol.enh_3d_on)
344 prescaler += wmc_vol.enh_3d_prescaler;
346 wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL, wmc_vol.dac_l - prescaler,
347 WMC_DVOL);
348 wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL, wmc_vol.dac_r - prescaler,
349 WMC_DVOL);
352 void audiohw_set_headphone_vol(int vol_l, int vol_r)
354 int prev_l = wmc_vol.vol_l;
355 int prev_r = wmc_vol.vol_r;
356 int dac_l, dac_r, hp_l, hp_r;
357 int mix_l, mix_r, boost_l, boost_r;
359 wmc_vol.vol_l = vol_l;
360 wmc_vol.vol_r = vol_r;
362 /* Mixers are synced to provide full volume range on both the analogue
363 * and digital pathways */
364 get_headphone_levels(vol_l, &dac_l, &hp_l, &mix_l, &boost_l);
365 get_headphone_levels(vol_r, &dac_r, &hp_r, &mix_r, &boost_r);
367 wmc_vol.dac_l = dac_l;
368 wmc_vol.dac_r = dac_r;
370 sync_prescaler();
372 wmc_write_masked(WMC_LEFT_MIXER_CTRL, mix_l << WMC_BYPLMIXVOL_POS,
373 WMC_BYPLMIXVOL);
374 wmc_write_masked(WMC_LEFT_ADC_BOOST_CTRL,
375 boost_l << WMC_L2_2BOOSTVOL_POS, WMC_L2_2BOOSTVOL);
376 wmc_write_masked(WMC_LOUT1_HP_VOLUME_CTRL, hp_l, WMC_AVOL);
378 wmc_write_masked(WMC_RIGHT_MIXER_CTRL, mix_r << WMC_BYPRMIXVOL_POS,
379 WMC_BYPRMIXVOL);
380 wmc_write_masked(WMC_RIGHT_ADC_BOOST_CTRL,
381 boost_r << WMC_R2_2BOOSTVOL_POS, WMC_R2_2BOOSTVOL);
382 wmc_write_masked(WMC_ROUT1_HP_VOLUME_CTRL, hp_r, WMC_AVOL);
384 if (vol_l > 0)
386 /* Not muted and going up from mute level? */
387 if (prev_l <= 0 && !wmc_vol.ahw_mute)
388 wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
390 else
392 /* Going to mute level? */
393 if (prev_l > 0)
394 wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
397 if (vol_r > 0)
399 /* Not muted and going up from mute level? */
400 if (prev_r <= 0 && !wmc_vol.ahw_mute)
401 wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
403 else
405 /* Going to mute level? */
406 if (prev_r > 0)
407 wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
411 static void audiohw_mute(bool mute)
413 wmc_vol.ahw_mute = mute;
415 /* No DAC mute here, please - take care of each enabled output. */
416 if (mute)
418 wmc_set(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
419 wmc_set(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
421 else
423 /* Unmute outputs not at mute level */
424 if (wmc_vol.vol_l > 0)
425 wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL, WMC_MUTE);
427 if (wmc_vol.vol_r > 0)
428 wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL, WMC_MUTE);
432 /* Equalizer - set the eq band level -12 to +12 dB. */
433 void audiohw_set_eq_band_gain(unsigned int band, int val)
435 if (band > 4)
436 return;
438 wmc_vol.band_gain[band] = val;
440 if (!wmc_vol.eq_on)
441 val = 0;
443 wmc_write_masked(band + WMC_EQ1_LOW_SHELF, 12 - val, WMC_EQG);
446 /* Equalizer - set the eq band frequency index. */
447 void audiohw_set_eq_band_frequency(unsigned int band, int val)
449 if (band > 4)
450 return;
452 wmc_write_masked(band + WMC_EQ1_LOW_SHELF,
453 val << WMC_EQC_POS, WMC_EQC);
456 /* Equalizer - set bandwidth for peaking filters to wide (!= 0) or
457 * narrow (0); only valid for peaking filter bands 1-3. */
458 void audiohw_set_eq_band_width(unsigned int band, int val)
460 if (band < 1 || band > 3)
461 return;
463 wmc_write_masked(band + WMC_EQ1_LOW_SHELF,
464 (val == 0) ? 0 : WMC_EQBW, WMC_EQBW);
467 /* Set prescaler to prevent clipping the output amp when applying positive
468 * gain to EQ bands. */
469 void audiohw_set_prescaler(int val)
471 wmc_vol.prescaler = val / 5; /* centibels->semi-decibels */
472 sync_prescaler();
475 /* Set the depth of the 3D effect */
476 void audiohw_set_depth_3d(int val)
478 wmc_vol.enh_3d_prescaler = 10*val / 15; /* -5 dB @ full setting */
479 wmc_vol.enh_3d = val;
481 if (!wmc_vol.enh_3d_on)
482 val = 0;
484 sync_prescaler();
485 wmc_write_masked(WMC_3D_CONTROL, val, WMC_DEPTH3D);
488 void audiohw_close(void)
490 /* 1. Mute all analogue outputs */
491 audiohw_mute(true);
492 audiohw_enable_headphone_jack(false);
494 /* 2. Disable power management register 1. R1 = 00 */
495 wmc_write(WMC_POWER_MANAGEMENT1, 0x000);
497 /* 3. Disable power management register 2. R2 = 00 */
498 wmc_write(WMC_POWER_MANAGEMENT2, 0x000);
500 /* 4. Disable power management register 3. R3 = 00 */
501 wmc_write(WMC_POWER_MANAGEMENT3, 0x000);
503 /* 5. Remove external power supplies. */
506 void audiohw_set_frequency(int fsel)
508 /* For 16.9344MHz MCLK, codec as master. */
509 static const struct
511 uint32_t plln : 8;
512 uint32_t pllk1 : 6;
513 uint32_t pllk2 : 9;
514 uint32_t pllk3 : 9;
515 unsigned char mclkdiv;
516 unsigned char filter;
517 } srctrl_table[HW_NUM_FREQ] =
519 [HW_FREQ_8] = /* PLL = 65.536MHz */
521 .plln = 7 | WMC_PLL_PRESCALE,
522 .pllk1 = 0x2f, /* 12414886 */
523 .pllk2 = 0x0b7,
524 .pllk3 = 0x1a6,
525 .mclkdiv = WMC_MCLKDIV_8, /* 2.0480 MHz */
526 .filter = WMC_SR_8KHZ,
528 [HW_FREQ_11] = /* PLL = off */
530 .mclkdiv = WMC_MCLKDIV_6, /* 2.8224 MHz */
531 .filter = WMC_SR_12KHZ,
533 [HW_FREQ_12] = /* PLL = 73.728 MHz */
535 .plln = 8 | WMC_PLL_PRESCALE,
536 .pllk1 = 0x2d, /* 11869595 */
537 .pllk2 = 0x08e,
538 .pllk3 = 0x19b,
539 .mclkdiv = WMC_MCLKDIV_6, /* 3.0720 MHz */
540 .filter = WMC_SR_12KHZ,
542 [HW_FREQ_16] = /* PLL = 65.536MHz */
544 .plln = 7 | WMC_PLL_PRESCALE,
545 .pllk1 = 0x2f, /* 12414886 */
546 .pllk2 = 0x0b7,
547 .pllk3 = 0x1a6,
548 .mclkdiv = WMC_MCLKDIV_4, /* 4.0960 MHz */
549 .filter = WMC_SR_16KHZ,
551 [HW_FREQ_22] = /* PLL = off */
553 .mclkdiv = WMC_MCLKDIV_3, /* 5.6448 MHz */
554 .filter = WMC_SR_24KHZ,
556 [HW_FREQ_24] = /* PLL = 73.728 MHz */
558 .plln = 8 | WMC_PLL_PRESCALE,
559 .pllk1 = 0x2d, /* 11869595 */
560 .pllk2 = 0x08e,
561 .pllk3 = 0x19b,
562 .mclkdiv = WMC_MCLKDIV_3, /* 6.1440 MHz */
563 .filter = WMC_SR_24KHZ,
565 [HW_FREQ_32] = /* PLL = 65.536MHz */
567 .plln = 7 | WMC_PLL_PRESCALE,
568 .pllk1 = 0x2f, /* 12414886 */
569 .pllk2 = 0x0b7,
570 .pllk3 = 0x1a6,
571 .mclkdiv = WMC_MCLKDIV_2, /* 8.1920 MHz */
572 .filter = WMC_SR_32KHZ,
574 [HW_FREQ_44] = /* PLL = off */
576 .mclkdiv = WMC_MCLKDIV_1_5, /* 11.2896 MHz */
577 .filter = WMC_SR_48KHZ,
579 [HW_FREQ_48] = /* PLL = 73.728 MHz */
581 .plln = 8 | WMC_PLL_PRESCALE,
582 .pllk1 = 0x2d, /* 11869595 */
583 .pllk2 = 0x08e,
584 .pllk3 = 0x19b,
585 .mclkdiv = WMC_MCLKDIV_1_5, /* 12.2880 MHz */
586 .filter = WMC_SR_48KHZ,
590 unsigned int plln;
591 unsigned int mclkdiv;
593 if ((unsigned)fsel >= HW_NUM_FREQ)
594 fsel = HW_FREQ_DEFAULT;
596 /* Setup filters. */
597 wmc_write(WMC_ADDITIONAL_CTRL, srctrl_table[fsel].filter);
599 plln = srctrl_table[fsel].plln;
600 mclkdiv = srctrl_table[fsel].mclkdiv;
602 if (plln != 0)
604 /* Using PLL to generate SYSCLK */
606 /* Program PLL. */
607 wmc_write(WMC_PLL_N, plln);
608 wmc_write(WMC_PLL_K1, srctrl_table[fsel].pllk1);
609 wmc_write(WMC_PLL_K2, srctrl_table[fsel].pllk2);
610 wmc_write(WMC_PLL_K3, srctrl_table[fsel].pllk3);
612 /* Turn on PLL. */
613 wmc_set(WMC_POWER_MANAGEMENT1, WMC_PLLEN);
615 /* Switch to PLL and set divider. */
616 wmc_write_masked(WMC_CLOCK_GEN_CTRL, mclkdiv | WMC_CLKSEL,
617 WMC_MCLKDIV | WMC_CLKSEL);
619 else
621 /* Switch away from PLL and set MCLKDIV. */
622 wmc_write_masked(WMC_CLOCK_GEN_CTRL, mclkdiv,
623 WMC_MCLKDIV | WMC_CLKSEL);
625 /* Turn off PLL. */
626 wmc_clear(WMC_POWER_MANAGEMENT1, WMC_PLLEN);
630 void audiohw_enable_tone_controls(bool enable)
632 int i;
633 wmc_vol.eq_on = enable;
634 audiohw_set_prescaler(wmc_vol.prescaler);
636 for (i = 0; i < 5; i++)
637 audiohw_set_eq_band_gain(i, wmc_vol.band_gain[i]);
640 void audiohw_enable_depth_3d(bool enable)
642 wmc_vol.enh_3d_on = enable;
643 audiohw_set_depth_3d(wmc_vol.enh_3d);
646 #ifdef HAVE_RECORDING
647 void audiohw_set_recsrc(int source, bool recording)
649 switch (source)
651 case AUDIO_SRC_PLAYBACK:
652 /* Disable all audio paths but DAC */
653 /* Disable ADCs */
654 wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN);
655 wmc_clear(WMC_POWER_MANAGEMENT2, WMC_ADCENL | WMC_ADCENR);
656 /* Disable bypass */
657 wmc_clear(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX);
658 wmc_clear(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX);
659 /* Disable IP BOOSTMIX and PGA */
660 wmc_clear(WMC_POWER_MANAGEMENT2, WMC_INPPGAENL | WMC_INPPGAENR |
661 WMC_BOOSTENL | WMC_BOOSTENR);
662 wmc_clear(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA |
663 WMC_LIP2INPPGA | WMC_RIP2INPPGA |
664 WMC_LIN2INPPGA | WMC_RIN2INPPGA);
665 wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
666 wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
667 break;
669 case AUDIO_SRC_FMRADIO:
670 if (recording)
672 /* Disable bypass */
673 wmc_clear(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX);
674 wmc_clear(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX);
675 /* Enable ADCs, IP BOOSTMIX and PGA, route L/R2 through PGA */
676 wmc_set(WMC_POWER_MANAGEMENT2, WMC_ADCENL | WMC_ADCENR |
677 WMC_BOOSTENL | WMC_BOOSTENR | WMC_INPPGAENL |
678 WMC_INPPGAENR);
679 wmc_set(WMC_ADC_CONTROL, WMC_ADCOSR | WMC_HPFEN);
680 /* PGA at 0dB with +20dB boost */
681 wmc_write_masked(WMC_LEFT_INP_PGA_GAIN_CTRL, 0x10, WMC_AVOL);
682 wmc_write_masked(WMC_RIGHT_INP_PGA_GAIN_CTRL, 0x10, WMC_AVOL);
683 wmc_set(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
684 wmc_set(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
685 /* Connect L/R2 inputs to PGA */
686 wmc_write_masked(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA |
687 WMC_LIN2INPPGA | WMC_RIN2INPPGA,
688 WMC_L2_2INPPGA | WMC_R2_2INPPGA |
689 WMC_LIP2INPPGA | WMC_RIP2INPPGA |
690 WMC_LIN2INPPGA | WMC_RIN2INPPGA);
692 else
694 /* Disable PGA and ADC, enable IP BOOSTMIX, route L/R2 directly to
695 * IP BOOSTMIX */
696 wmc_clear(WMC_ADC_CONTROL, WMC_HPFEN);
697 wmc_write_masked(WMC_POWER_MANAGEMENT2, WMC_BOOSTENL | WMC_BOOSTENR,
698 WMC_BOOSTENL | WMC_BOOSTENR | WMC_INPPGAENL |
699 WMC_INPPGAENR | WMC_ADCENL | WMC_ADCENR);
700 wmc_clear(WMC_INPUT_CTRL, WMC_L2_2INPPGA | WMC_R2_2INPPGA |
701 WMC_LIP2INPPGA | WMC_RIP2INPPGA |
702 WMC_LIN2INPPGA | WMC_RIN2INPPGA);
703 wmc_clear(WMC_LEFT_ADC_BOOST_CTRL, WMC_PGABOOSTL);
704 wmc_clear(WMC_RIGHT_ADC_BOOST_CTRL, WMC_PGABOOSTR);
705 /* Enable bypass to L/R mixers */
706 wmc_set(WMC_LEFT_MIXER_CTRL, WMC_BYPL2LMIX);
707 wmc_set(WMC_RIGHT_MIXER_CTRL, WMC_BYPR2RMIX);
709 break;
713 void audiohw_set_recvol(int left, int right, int type)
715 switch (type)
717 case AUDIO_GAIN_LINEIN:
718 wmc_write_masked(WMC_LEFT_ADC_DIGITAL_VOL, left + 239, WMC_DVOL);
719 wmc_write_masked(WMC_RIGHT_ADC_DIGITAL_VOL, right + 239, WMC_DVOL);
720 return;
723 #endif /* HAVE_RECORDING */