1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2008 by Michael Sevakis
12 * Driver for WM8978 audio codec
14 * All files in this archive are subject to the GNU General Public License.
15 * See the file COPYING in the source tree root for full license agreement.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
29 /* #define to help adjust lower volume limit */
33 #define HW_VOL_ANA_MIN 0
34 #define HW_VOL_ANA_MAX 63
35 #define HW_VOL_DIG_MAX 255
36 #define HW_VOL_DIG_THRESHOLD (HW_VOL_MAX - HW_VOL_ANA_MAX)
37 #define HW_VOL_DIG_MIN (HW_VOL_DIG_MAX - 2*HW_VOL_DIG_THRESHOLD)
39 /* TODO: Define/refine an API for special hardware steps outside the
40 * main codec driver such as special GPIO handling. */
41 extern void audiohw_enable_headphone_jack(bool enable
);
43 const struct sound_settings_info audiohw_settings
[] =
45 [SOUND_VOLUME
] = {"dB", 0, 1, -90, 6, -25},
46 [SOUND_BASS
] = {"dB", 0, 1, -12, 12, 0},
47 [SOUND_TREBLE
] = {"dB", 0, 1, -12, 12, 0},
48 [SOUND_BALANCE
] = {"%", 0, 1,-100, 100, 0},
49 [SOUND_CHANNELS
] = {"", 0, 1, 0, 5, 0},
50 [SOUND_STEREO_WIDTH
] = {"%", 0, 5, 0, 250, 100},
51 [SOUND_LEFT_GAIN
] = {"dB", 1, 1,-128, 96, 0},
52 [SOUND_RIGHT_GAIN
] = {"dB", 1, 1,-128, 96, 0},
54 [SOUND_MIC_GAIN
] = {"dB", 1, 1,-128, 108, 16},
57 [SOUND_BASS_CUTOFF
] = {"", 0, 1, 1, 4, 1},
58 [SOUND_TREBLE_CUTOFF
] = {"", 0, 1, 1, 4, 1},
62 static uint16_t wmc_regs
[WMC_NUM_REGISTERS
] =
64 /* Initialized with post-reset default values - the 2-wire interface
65 * cannot be read. Or-in additional bits desired for some registers. */
66 [0 ... WMC_NUM_REGISTERS
-1] = 0x8000, /* To ID invalids in gaps */
67 [WMC_SOFTWARE_RESET
] = 0x000,
68 [WMC_POWER_MANAGEMENT1
] = 0x000,
69 [WMC_POWER_MANAGEMENT2
] = 0x000,
70 [WMC_POWER_MANAGEMENT3
] = 0x000,
71 [WMC_AUDIO_INTERFACE
] = 0x050,
72 [WMC_COMPANDING_CTRL
] = 0x000,
73 [WMC_CLOCK_GEN_CTRL
] = 0x140,
74 [WMC_ADDITIONAL_CTRL
] = 0x000,
76 [WMC_JACK_DETECT_CONTROL1
] = 0x000,
77 [WMC_DAC_CONTROL
] = 0x000,
78 [WMC_LEFT_DAC_DIGITAL_VOL
] = 0x0ff | WMC_VU
,
79 [WMC_RIGHT_DAC_DIGITAL_VOL
] = 0x0ff | WMC_VU
,
80 [WMC_JACK_DETECT_CONTROL2
] = 0x000,
81 [WMC_ADC_CONTROL
] = 0x100,
82 [WMC_LEFT_ADC_DIGITAL_VOL
] = 0x0ff | WMC_VU
,
83 [WMC_RIGHT_ADC_DIGITAL_VOL
] = 0x0ff | WMC_VU
,
84 [WMC_EQ1_LOW_SHELF
] = 0x12c,
85 [WMC_EQ2_PEAK1
] = 0x02c,
86 [WMC_EQ3_PEAK2
] = 0x02c,
87 [WMC_EQ4_PEAK3
] = 0x02c,
88 [WMC_EQ5_HIGH_SHELF
] = 0x02c,
89 [WMC_DAC_LIMITER1
] = 0x032,
90 [WMC_DAC_LIMITER2
] = 0x000,
91 [WMC_NOTCH_FILTER1
] = 0x000,
92 [WMC_NOTCH_FILTER2
] = 0x000,
93 [WMC_NOTCH_FILTER3
] = 0x000,
94 [WMC_NOTCH_FILTER4
] = 0x000,
95 [WMC_ALC_CONTROL1
] = 0x038,
96 [WMC_ALC_CONTROL2
] = 0x00b,
97 [WMC_ALC_CONTROL3
] = 0x032,
98 [WMC_NOISE_GATE
] = 0x000,
100 [WMC_PLL_K1
] = 0x00c,
101 [WMC_PLL_K2
] = 0x093,
102 [WMC_PLL_K3
] = 0x0e9,
103 [WMC_3D_CONTROL
] = 0x000,
104 [WMC_BEEP_CONTROL
] = 0x000,
105 [WMC_INPUT_CTRL
] = 0x033,
106 [WMC_LEFT_INP_PGA_GAIN_CTRL
] = 0x010,
107 [WMC_RIGHT_INP_PGA_GAIN_CTRL
] = 0x010,
108 [WMC_LEFT_ADC_BOOST_CTRL
] = 0x100,
109 [WMC_RIGHT_ADC_BOOST_CTRL
] = 0x100,
110 [WMC_OUTPUT_CTRL
] = 0x002,
111 [WMC_LEFT_MIXER_CTRL
] = 0x001,
112 [WMC_RIGHT_MIXER_CTRL
] = 0x001,
113 [WMC_LOUT1_HP_VOLUME_CTRL
] = 0x039 | WMC_VU
| WMC_ZC
,
114 [WMC_ROUT1_HP_VOLUME_CTRL
] = 0x039 | WMC_VU
| WMC_ZC
,
115 [WMC_LOUT2_SPK_VOLUME_CTRL
] = 0x039 | WMC_VU
| WMC_ZC
,
116 [WMC_ROUT2_SPK_VOLUME_CTRL
] = 0x039 | WMC_VU
| WMC_ZC
,
117 [WMC_OUT3_MIXER_CTRL
] = 0x001,
118 [WMC_OUT4_MONO_MIXER_CTRL
] = 0x001,
128 HW_VOL_MUTE
, HW_VOL_MUTE
, false
131 static void wmc_write(unsigned int reg
, unsigned int val
)
133 if (reg
>= WMC_NUM_REGISTERS
|| (wmc_regs
[reg
] & 0x8000))
135 logf("wm8978 invalid register: %d", reg
);
139 wmc_regs
[reg
] = val
& ~0x8000;
140 wmcodec_write(reg
, val
);
143 static void wmc_set(unsigned int reg
, unsigned int bits
)
145 wmc_write(reg
, wmc_regs
[reg
] | bits
);
148 static void wmc_clear(unsigned int reg
, unsigned int bits
)
150 wmc_write(reg
, wmc_regs
[reg
] & ~bits
);
153 static void wmc_write_masked(unsigned int reg
, unsigned int bits
,
156 wmc_write(reg
, (wmc_regs
[reg
] & ~mask
) | (bits
& mask
));
159 /* convert tenth of dB volume (-890..60) to master volume register value
160 * (000000...111111) */
161 int tenthdb2master(int db
)
163 /* -90dB to +6dB 1dB steps (96 levels) 7bits */
164 /* 1100000 == +6dB (0x60,96) */
165 /* 1101010 == 0dB (0x5a,90) */
166 /* 1000001 == -57dB (0x21,33,DAC) */
167 /* 0000001 == -89dB (0x01,01) */
168 /* 0000000 == -90dB (0x00,00,Mute) */
169 if (db
<= VOLUME_MIN
)
175 return (db
- VOLUME_MIN
) / 10;
179 void audiohw_preinit(void)
181 /* 1. Turn on external power supplies. Wait for supply voltage to settle. */
183 /* Step 1 should be completed already. Reset and return all registers to
185 wmcodec_write(WMC_SOFTWARE_RESET
, 0xff);
188 /* 2. Mute all analogue outputs */
189 wmc_set(WMC_LOUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
190 wmc_set(WMC_ROUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
191 wmc_set(WMC_LOUT2_SPK_VOLUME_CTRL
, WMC_MUTE
);
192 wmc_set(WMC_ROUT2_SPK_VOLUME_CTRL
, WMC_MUTE
);
193 wmc_set(WMC_OUT3_MIXER_CTRL
, WMC_MUTE
);
194 wmc_set(WMC_OUT4_MONO_MIXER_CTRL
, WMC_MUTE
);
195 wmc_set(WMC_INPUT_CTRL
, 0x000);
197 /* 3. Set L/RMIXEN = 1 and DACENL/R = 1 in register R3. */
198 wmc_write(WMC_POWER_MANAGEMENT3
,
199 WMC_RMIXEN
| WMC_LMIXEN
| WMC_DACENR
| WMC_DACENL
);
201 /* 4. Set BUFIOEN = 1 and VMIDSEL[1:0] to required value in register
202 * R1. Wait for VMID supply to settle */
203 wmc_write(WMC_POWER_MANAGEMENT1
, WMC_BUFIOEN
| WMC_VMIDSEL_300K
);
206 /* 5. Set BIASEN = 1 in register R1. */
207 wmc_set(WMC_POWER_MANAGEMENT1
, WMC_BIASEN
);
210 void audiohw_postinit(void)
214 /* 6. Set L/ROUTEN = 1 in register R2. */
215 wmc_write(WMC_POWER_MANAGEMENT2
, WMC_LOUT1EN
| WMC_ROUT1EN
);
217 /* 7. Enable other mixers as required */
219 /* 8. Enable other outputs as required */
221 /* 9. Set remaining registers */
222 wmc_write(WMC_AUDIO_INTERFACE
, WMC_WL_16
| WMC_FMT_I2S
223 | WMC_DACLRSWAP
| WMC_ADCLRSWAP
);
224 wmc_write(WMC_DAC_CONTROL
, WMC_DACOSR_128
| WMC_AMUTE
);
226 /* Specific to HW clocking */
227 wmc_write(WMC_CLOCK_GEN_CTRL
, WMC_MCLKDIV_1_5
| WMC_BCLKDIV_8
| WMC_MS
);
228 wmc_write(WMC_ADDITIONAL_CTRL
, WMC_SR_48KHZ
); /* 44.1 */
230 /* Initialize to minimum volume */
231 wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL
, HW_VOL_DIG_MIN
, WMC_DVOL
);
232 wmc_write_masked(WMC_LOUT1_HP_VOLUME_CTRL
, HW_VOL_ANA_MIN
, WMC_AVOL
);
233 wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL
, HW_VOL_DIG_MIN
, WMC_DVOL
);
234 wmc_write_masked(WMC_ROUT1_HP_VOLUME_CTRL
, HW_VOL_ANA_MIN
, WMC_AVOL
);
237 wmc_write_masked(WMC_LEFT_ADC_DIGITAL_VOL
, 0x00, WMC_DVOL
);
238 wmc_write_masked(WMC_RIGHT_ADC_DIGITAL_VOL
, 0x00, WMC_DVOL
);
240 audiohw_enable_headphone_jack(true);
243 void audiohw_set_headphone_vol(int vol_l
, int vol_r
)
245 int prev_l
= wmc_vol
.vol_l
;
246 int prev_r
= wmc_vol
.vol_r
;
249 wmc_vol
.vol_l
= vol_l
;
250 wmc_vol
.vol_r
= vol_r
;
252 /* When analogue volume falls below -57dB (0x00) start attenuating the
254 if (vol_l
>= HW_VOL_DIG_THRESHOLD
)
256 if (vol_l
> HW_VOL_MAX
)
259 dac_l
= HW_VOL_DIG_MAX
;
260 vol_l
-= HW_VOL_DIG_THRESHOLD
;
264 if (vol_l
< HW_VOL_MIN
)
267 dac_l
= 2*vol_l
+ HW_VOL_DIG_MIN
;
268 vol_l
= HW_VOL_ANA_MIN
;
271 if (vol_r
>= HW_VOL_DIG_THRESHOLD
)
273 if (vol_r
> HW_VOL_MAX
)
276 dac_r
= HW_VOL_DIG_MAX
;
277 vol_r
-= HW_VOL_DIG_THRESHOLD
;
281 if (vol_r
< HW_VOL_MIN
)
284 dac_r
= 2*vol_r
+ HW_VOL_DIG_MIN
;
285 vol_r
= HW_VOL_ANA_MIN
;
288 /* Have to write both channels always to have the latching work */
289 wmc_write_masked(WMC_LEFT_DAC_DIGITAL_VOL
, dac_l
, WMC_DVOL
);
290 wmc_write_masked(WMC_LOUT1_HP_VOLUME_CTRL
, vol_l
, WMC_AVOL
);
291 wmc_write_masked(WMC_RIGHT_DAC_DIGITAL_VOL
, dac_r
, WMC_DVOL
);
292 wmc_write_masked(WMC_ROUT1_HP_VOLUME_CTRL
, vol_r
, WMC_AVOL
);
294 if (wmc_vol
.vol_l
> HW_VOL_MUTE
)
296 /* Not muted and going up from mute level? */
297 if (prev_l
<= HW_VOL_MUTE
&& !wmc_vol
.ahw_mute
)
298 wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
302 /* Going to mute level? */
303 if (prev_l
> HW_VOL_MUTE
)
304 wmc_set(WMC_LOUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
307 if (wmc_vol
.vol_r
> HW_VOL_MUTE
)
309 /* Not muted and going up from mute level? */
310 if (prev_r
<= HW_VOL_MIN
&& !wmc_vol
.ahw_mute
)
311 wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
315 /* Going to mute level? */
316 if (prev_r
> HW_VOL_MUTE
)
317 wmc_set(WMC_ROUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
321 void audiohw_close(void)
323 /* 1. Mute all analogue outputs */
325 audiohw_enable_headphone_jack(false);
327 /* 2. Disable power management register 1. R1 = 00 */
328 wmc_write(WMC_POWER_MANAGEMENT1
, 0x000);
330 /* 3. Disable power management register 2. R2 = 00 */
331 wmc_write(WMC_POWER_MANAGEMENT2
, 0x000);
333 /* 4. Disable power management register 3. R3 = 00 */
334 wmc_write(WMC_POWER_MANAGEMENT3
, 0x000);
336 /* 5. Remove external power supplies. */
339 void audiohw_mute(bool mute
)
341 wmc_vol
.ahw_mute
= mute
;
343 /* No DAC mute here, please - take care of each enabled output. */
346 wmc_set(WMC_LOUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
347 wmc_set(WMC_ROUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
351 /* Unmute outputs not at mute level */
352 if (wmc_vol
.vol_l
> HW_VOL_MUTE
)
353 wmc_clear(WMC_LOUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
355 if (wmc_vol
.vol_r
> HW_VOL_MUTE
)
356 wmc_clear(WMC_ROUT1_HP_VOLUME_CTRL
, WMC_MUTE
);
361 #ifdef HAVE_RECORDING
363 void audiohw_set_recvol(int left
, int right
, int type
)
365 (void)left
; (void)right
; (void)type
;