1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Driver for WM8975 audio codec
12 * Based on code from the ipodlinux project - http://ipodlinux.org/
13 * Adapted for Rockbox in December 2005
15 * Original file: linux/arch/armnommu/mach-ipod/audio.c
17 * Copyright (c) 2003-2005 Bernard Leach (leachbj@bouncycastle.org)
19 * This program is free software; you can redistribute it and/or
20 * modify it under the terms of the GNU General Public License
21 * as published by the Free Software Foundation; either version 2
22 * of the License, or (at your option) any later version.
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
25 * KIND, either express or implied.
27 ****************************************************************************/
37 const struct sound_settings_info audiohw_settings
[] = {
38 [SOUND_VOLUME
] = {"dB", 0, 1, -74, 6, -25},
39 [SOUND_BASS
] = {"dB", 0, 1, -6, 9, 0},
40 [SOUND_TREBLE
] = {"dB", 0, 1, -6, 9, 0},
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},
45 [SOUND_LEFT_GAIN
] = {"dB", 1, 1, 0, 63, 23},
46 [SOUND_RIGHT_GAIN
] = {"dB", 1, 1, 0, 63, 23},
47 [SOUND_MIC_GAIN
] = {"dB", 1, 1, 0, 63, 0},
51 static unsigned short wm8975_regs
[] =
53 [LINVOL
] = LINVOL_LZCEN
| 23, /* 0dB */
54 [RINVOL
] = RINVOL_RIVU
| RINVOL_RZCEN
| 23, /* 0dB */
55 [DAPCTRL
] = DAPCTRL_DACMU
,
56 [PWRMGMT1
] = PWRMGMT1_VMIDSEL_5K
| PWRMGMT1_VREF
,
57 [PWRMGMT2
] = PWRMGMT2_DACL
| PWRMGMT2_DACR
| PWRMGMT2_LOUT1
58 | PWRMGMT2_ROUT1
| PWRMGMT2_LOUT2
| PWRMGMT2_ROUT2
,
61 static void wm8975_write(int reg
, unsigned val
)
63 wm8975_regs
[reg
] = val
;
64 wmcodec_write(reg
, val
);
67 static void wm8975_write_and(int reg
, unsigned bits
)
69 wm8975_write(reg
, wm8975_regs
[reg
] & bits
);
72 static void wm8975_write_or(int reg
, unsigned bits
)
74 wm8975_write(reg
, wm8975_regs
[reg
] | bits
);
77 /* convert tenth of dB volume (-730..60) to master volume register value */
78 int tenthdb2master(int db
)
80 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
81 /* 1111111 == +6dB (0x7f) */
82 /* 1111001 == 0dB (0x79) */
83 /* 0110000 == -73dB (0x30 */
84 /* 0101111..0000000 == mute (0x2f) */
86 if (db
< VOLUME_MIN
) {
89 return((db
/10)+73+0x30);
93 int sound_val2phys(int setting
, int value
)
100 case SOUND_LEFT_GAIN
:
101 case SOUND_RIGHT_GAIN
:
102 result
= ((value
- 23) * 15) / 2;
105 result
= ((value
- 23) * 15) / 2 + 200;
116 void audiohw_mute(bool mute
)
119 /* Set DACMU = 1 to soft-mute the audio DACs. */
120 wm8975_write_or(DAPCTRL
, DAPCTRL_DACMU
);
122 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
123 wm8975_write_and(DAPCTRL
, ~DAPCTRL_DACMU
);
127 #define IPOD_PCM_LEVEL 0x65 /* -6dB */
129 void audiohw_preinit(void)
131 /* POWER UP SEQUENCE */
132 wmcodec_write(RESET
, RESET_RESET
);
134 /* 2. Enable Vmid and VREF, quick startup. */
135 wm8975_write(PWRMGMT1
, wm8975_regs
[PWRMGMT1
]);
137 wm8975_regs
[PWRMGMT1
] &= ~PWRMGMT1_VMIDSEL_MASK
;
138 wm8975_write(PWRMGMT1
, wm8975_regs
[PWRMGMT1
] | PWRMGMT1_VMIDSEL_50K
);
140 /* 4. Enable DACs, line and headphone output buffers as required. */
141 wm8975_write(PWRMGMT2
, wm8975_regs
[PWRMGMT2
]);
143 wmcodec_write(AINTFCE
, AINTFCE_MS
| AINTFCE_LRP_I2S_RLO
144 | AINTFCE_IWL_16BIT
| AINTFCE_FORMAT_I2S
);
146 wm8975_write(DAPCTRL
, wm8975_regs
[DAPCTRL
] );
148 /* Still need to find out why this is neccessary */
150 wmcodec_write(SAMPCTRL
, 0);
152 wmcodec_write(SAMPCTRL
, WM8975_44100HZ
);
155 /* set the volume to -6dB */
156 wmcodec_write(LOUT1VOL
, LOUT1VOL_LO1ZC
| IPOD_PCM_LEVEL
);
157 wmcodec_write(ROUT1VOL
, ROUT1VOL_RO1VU
| ROUT1VOL_RO1ZC
| IPOD_PCM_LEVEL
);
159 wmcodec_write(LOUTMIX1
, LOUTMIX1_LD2LO
| LOUTMIX1_LI2LOVOL(5));
160 wmcodec_write(LOUTMIX2
, LOUTMIX2_RI2LOVOL(5));
162 wmcodec_write(ROUTMIX1
, ROUTMIX1_LI2ROVOL(5));
163 wmcodec_write(ROUTMIX2
, ROUTMIX2_RD2RO
| ROUTMIX2_RI2ROVOL(5));
165 wmcodec_write(MOUTMIX1
, 0);
166 wmcodec_write(MOUTMIX2
, 0);
169 void audiohw_postinit(void)
175 void audiohw_set_master_vol(int vol_l
, int vol_r
)
177 /* +6 to -73dB 1dB steps (plus mute == 80levels) 7bits */
178 /* 1111111 == +6dB */
180 /* 0110000 == -73dB */
181 /* 0101111 == mute (0x2f) */
184 wmcodec_write(LOUT1VOL
, LOUT1VOL_LO1ZC
| vol_l
);
185 wmcodec_write(ROUT1VOL
, ROUT1VOL_RO1VU
| ROUT1VOL_RO1ZC
| vol_r
);
188 void audiohw_set_lineout_vol(int vol_l
, int vol_r
)
191 wmcodec_write(LOUT2VOL
, LOUT2VOL_LO2ZC
| vol_l
);
192 wmcodec_write(ROUT2VOL
, ROUT2VOL_RO2VU
| ROUT2VOL_RO2ZC
| vol_r
);
195 void audiohw_set_bass(int value
)
197 const int regvalues
[] = {
198 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 2, 1
201 if ((value
>= -6) && (value
<= 9)) {
202 /* We use linear bass control with 200 Hz cutoff */
203 wmcodec_write(BASSCTRL
, regvalues
[value
+ 6] | BASSCTRL_BC
);
207 void audiohw_set_treble(int value
)
209 const int regvalues
[] = {
210 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 2, 1
213 if ((value
>= -6) && (value
<= 9)) {
214 /* We use linear treble control with 4 kHz cutoff */
215 wmcodec_write(TREBCTRL
, regvalues
[value
+ 6] | TREBCTRL_TC
);
219 /* Nice shutdown of WM8975 codec */
220 void audiohw_close(void)
224 /* 2. Disable all output buffers. */
225 wmcodec_write(PWRMGMT2
, 0x0);
227 /* 3. Switch off the power supplies. */
228 wmcodec_write(PWRMGMT1
, 0x0);
231 /* Note: Disable output before calling this function */
232 void audiohw_set_frequency(int fsel
)
237 #ifdef HAVE_RECORDING
238 void audiohw_enable_recording(bool source_mic
)
240 wm8975_regs
[PWRMGMT1
] |= PWRMGMT1_AINL
| PWRMGMT1_AINR
241 | PWRMGMT1_ADCL
| PWRMGMT1_ADCR
;
242 wm8975_write(PWRMGMT1
, wm8975_regs
[PWRMGMT1
]);
244 /* NOTE: When switching to digital monitoring we will not want
245 * the DACs disabled. Also the outputs shouldn't be disabled
246 * when recording from line in (dock connector) - needs testing. */
247 wm8975_regs
[PWRMGMT2
] &= ~(PWRMGMT2_LOUT1
| PWRMGMT2_ROUT1
248 | PWRMGMT2_LOUT2
| PWRMGMT2_ROUT2
);
249 wm8975_write(PWRMGMT2
, wm8975_regs
[PWRMGMT2
]);
251 wm8975_write_or(LINVOL
, LINVOL_LINMUTE
);
252 wm8975_write_or(RINVOL
, RINVOL_RINMUTE
);
254 wmcodec_write(ADDCTRL3
, ADDCTRL3_VROI
);
257 wmcodec_write(ADDCTRL1
, ADDCTRL1_VSEL_LOWBIAS
| ADDCTRL1_DATSEL_RADC
259 wmcodec_write(ADCLPATH
, 0);
260 wmcodec_write(ADCRPATH
, ADCRPATH_RINSEL_RIN2
| ADCRPATH_RMICBOOST_20dB
);
262 wmcodec_write(ADDCTRL1
, ADDCTRL1_VSEL_LOWBIAS
| ADDCTRL1_DATSEL_NORMAL
264 wmcodec_write(ADCLPATH
, ADCLPATH_LINSEL_LIN1
| ADCLPATH_LMICBOOST_OFF
);
265 wmcodec_write(ADCRPATH
, ADCRPATH_RINSEL_RIN1
| ADCRPATH_RMICBOOST_OFF
);
267 wm8975_write_and(LINVOL
, ~LINVOL_LINMUTE
);
268 wm8975_write_and(RINVOL
, ~RINVOL_RINMUTE
);
271 void audiohw_disable_recording(void)
274 wm8975_write_or(LINVOL
, LINVOL_LINMUTE
);
275 wm8975_write_or(RINVOL
, RINVOL_RINMUTE
);
277 wmcodec_write(ADDCTRL3
, 0);
279 wm8975_regs
[PWRMGMT2
] |= PWRMGMT2_DACL
| PWRMGMT2_DACR
280 | PWRMGMT2_LOUT1
| PWRMGMT2_ROUT1
281 | PWRMGMT2_LOUT2
| PWRMGMT2_ROUT2
;
282 wm8975_write(PWRMGMT2
, wm8975_regs
[PWRMGMT2
]);
284 wm8975_regs
[PWRMGMT1
] &= ~(PWRMGMT1_AINL
| PWRMGMT1_AINR
285 | PWRMGMT1_ADCL
| PWRMGMT1_ADCR
);
286 wm8975_write(PWRMGMT1
, wm8975_regs
[PWRMGMT1
]);
289 void audiohw_set_recvol(int left
, int right
, int type
)
293 case AUDIO_GAIN_MIC
: /* Mic uses right ADC */
294 wm8975_regs
[RINVOL
] &= ~RINVOL_MASK
;
295 wm8975_write_or(RINVOL
, left
& RINVOL_MASK
);
297 case AUDIO_GAIN_LINEIN
:
298 wm8975_regs
[LINVOL
] &= ~LINVOL_MASK
;
299 wm8975_write_or(LINVOL
, left
& LINVOL_MASK
);
300 wm8975_regs
[RINVOL
] &= ~RINVOL_MASK
;
301 wm8975_write_or(RINVOL
, right
& RINVOL_MASK
);
308 void audiohw_set_monitor(bool enable
)
312 #endif /* HAVE_RECORDING */