summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--firmware/drivers/audio/wm8731.c162
-rw-r--r--firmware/export/wm8731.h2
2 files changed, 86 insertions, 78 deletions
diff --git a/firmware/drivers/audio/wm8731.c b/firmware/drivers/audio/wm8731.c
index d96701ca9d..d6e21c34de 100644
--- a/firmware/drivers/audio/wm8731.c
+++ b/firmware/drivers/audio/wm8731.c
@@ -53,33 +53,43 @@ const struct sound_settings_info audiohw_settings[] = {
53 53
54/* Init values/shadows 54/* Init values/shadows
55 * Ignore bit 8 since that only specifies "both" for updating 55 * Ignore bit 8 since that only specifies "both" for updating
56 * gains */ 56 * gains - "RESET" (15h) not included */
57static unsigned char wm8731_regs[7] = 57static unsigned char wm8731_regs[WM8731_NUM_REGS] =
58{ 58{
59 [LINVOL] = LINVOL_LINMUTE, 59 [LINVOL] = 0x97,
60 [RINVOL] = RINVOL_RINMUTE, 60 [RINVOL] = 0x97,
61 [LOUTVOL] = ROUTVOL_RZCEN, 61 [LOUTVOL] = 0x79 | ROUTVOL_RZCEN,
62 [ROUTVOL] = ROUTVOL_RZCEN, 62 [ROUTVOL] = 0x79 | ROUTVOL_RZCEN,
63 [AAPCTRL] = AAPCTRL_MUTEMIC | AAPCTRL_DACSEL, 63 [AAPCTRL] = 0x0a,
64 [DAPCTRL] = DAPCTRL_DACMU, 64 [DAPCTRL] = 0x08,
65 [PDCTRL] = PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_ADCPD | 65 [PDCTRL] = 0x9f,
66 PDCTRL_OUTPD | PDCTRL_OSCPD | PDCTRL_CLKOUTPD, 66 [AINTFCE] = 0x0a,
67 [SAMPCTRL] = 0x00,
68 [ACTIVECTRL] = 0x00,
67}; 69};
68 70
69static void wm8731_write(int reg, unsigned val) 71static void wm8731_write(int reg, unsigned val)
70{ 72{
73 if ((unsigned)reg >= WM8731_NUM_REGS)
74 return;
75
71 wm8731_regs[reg] = (unsigned char)val; 76 wm8731_regs[reg] = (unsigned char)val;
72 wmcodec_write(reg, val); 77 wmcodec_write(reg, val);
73} 78}
74 79
75static void wm8731_write_and(int reg, unsigned bits) 80static void wm8731_set(int reg, unsigned bits)
76{ 81{
77 wm8731_write(reg, wm8731_regs[reg] & bits); 82 wm8731_write(reg, wm8731_regs[reg] | bits);
78} 83}
79 84
80static void wm8731_write_or(int reg, unsigned bits) 85static void wm8731_clear(int reg, unsigned bits)
81{ 86{
82 wm8731_write(reg, wm8731_regs[reg] | bits); 87 wm8731_write(reg, wm8731_regs[reg] & ~bits);
88}
89
90static void wm8731_write_masked(int reg, unsigned bits, unsigned mask)
91{
92 wm8731_write(reg, (wm8731_regs[reg] & ~mask) | (bits & mask));
83} 93}
84 94
85/* convert tenth of dB volume (-730..60) to master volume register value */ 95/* convert tenth of dB volume (-730..60) to master volume register value */
@@ -125,17 +135,17 @@ void audiohw_mute(bool mute)
125{ 135{
126 if (mute) { 136 if (mute) {
127 /* Set DACMU = 1 to soft-mute the audio DACs. */ 137 /* Set DACMU = 1 to soft-mute the audio DACs. */
128 wm8731_write_or(DAPCTRL, DAPCTRL_DACMU); 138 wm8731_set(DAPCTRL, DAPCTRL_DACMU);
129 } else { 139 } else {
130 /* Set DACMU = 0 to soft-un-mute the audio DACs. */ 140 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
131 wm8731_write_and(DAPCTRL, ~DAPCTRL_DACMU); 141 wm8731_clear(DAPCTRL, DAPCTRL_DACMU);
132 } 142 }
133} 143}
134 144
135static void codec_set_active(int active) 145static void codec_set_active(int active)
136{ 146{
137 /* set active to 0x0 or 0x1 */ 147 /* set active to 0x0 or 0x1 */
138 wmcodec_write(ACTIVECTRL, active ? ACTIVECTRL_ACTIVE : 0); 148 wm8731_write(ACTIVECTRL, active ? ACTIVECTRL_ACTIVE : 0);
139} 149}
140 150
141void audiohw_preinit(void) 151void audiohw_preinit(void)
@@ -150,23 +160,22 @@ void audiohw_preinit(void)
150 160
151 /* 2) Set all required bits in the Power Down register (0Ch) to '0'; 161 /* 2) Set all required bits in the Power Down register (0Ch) to '0';
152 * EXCEPT the OUTPD bit, this should be set to '1' (Default). */ 162 * EXCEPT the OUTPD bit, this should be set to '1' (Default). */
153 wm8731_write(PDCTRL, wm8731_regs[PDCTRL]); 163 wm8731_clear(PDCTRL, PDCTRL_DACPD | PDCTRL_POWEROFF);
154 164
155 /* 3) Set required values in all other registers except 12h (Active). */ 165 /* 3) Set required values in all other registers except 12h (Active). */
156 wmcodec_write(AINTFCE, AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT | 166 wm8731_write(AINTFCE,
157#ifdef CODEC_SLAVE 167#ifndef CODEC_SLAVE
158 0); 168 AINTFCE_MS |
159#else
160 AINTFCE_MS);
161#endif 169#endif
162 wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]); 170 AINTFCE_FORMAT_I2S | AINTFCE_IWL_16BIT);
163 wm8731_write(DAPCTRL, wm8731_regs[DAPCTRL]); 171
164 wmcodec_write(SAMPCTRL, WM8731_USB24_44100HZ); 172 wm8731_set(AAPCTRL, AAPCTRL_DACSEL);
173 wm8731_write(SAMPCTRL, WM8731_USB24_44100HZ);
165 174
166 /* 5) The last write of the sequence should be setting OUTPD to '0' 175 /* 5) The last write of the sequence should be setting OUTPD to '0'
167 * (active) in register 0Ch, enabling the DAC signal path, free 176 * (active) in register 0Ch, enabling the DAC signal path, free
168 * of any significant power-up noise. */ 177 * of any significant power-up noise. */
169 wm8731_write_and(PDCTRL, ~PDCTRL_OUTPD); 178 wm8731_clear(PDCTRL, PDCTRL_OUTPD);
170} 179}
171 180
172void audiohw_postinit(void) 181void audiohw_postinit(void)
@@ -180,7 +189,7 @@ void audiohw_postinit(void)
180 189
181#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) 190#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
182 /* We need to enable bit 4 of GPIOL for output for sound on H10 */ 191 /* We need to enable bit 4 of GPIOL for output for sound on H10 */
183 GPIOL_OUTPUT_VAL |= 0x10; 192 GPIO_SET_BITWISE(GPIOL_OUTPUT_VAL, 0x10);
184#endif 193#endif
185} 194}
186 195
@@ -191,8 +200,8 @@ void audiohw_set_master_vol(int vol_l, int vol_r)
191 /* 1111001 == 0dB */ 200 /* 1111001 == 0dB */
192 /* 0110000 == -73dB */ 201 /* 0110000 == -73dB */
193 /* 0101111 == mute (0x2f) */ 202 /* 0101111 == mute (0x2f) */
194 wm8731_write(LOUTVOL, LOUTVOL_LZCEN | (vol_l & LOUTVOL_LHPVOL_MASK)); 203 wm8731_write_masked(LOUTVOL, vol_l, LOUTVOL_LHPVOL_MASK);
195 wm8731_write(ROUTVOL, ROUTVOL_RZCEN | (vol_r & ROUTVOL_RHPVOL_MASK)); 204 wm8731_write_masked(ROUTVOL, vol_r, ROUTVOL_RHPVOL_MASK);
196} 205}
197 206
198/* Nice shutdown of WM8731 codec */ 207/* Nice shutdown of WM8731 codec */
@@ -200,13 +209,14 @@ void audiohw_close(void)
200{ 209{
201 /* POWER DOWN SEQUENCE */ 210 /* POWER DOWN SEQUENCE */
202 /* 1) Set the OUTPD bit to '1' (power down). */ 211 /* 1) Set the OUTPD bit to '1' (power down). */
203 wm8731_write_or(PDCTRL, PDCTRL_OUTPD); 212 wm8731_set(PDCTRL, PDCTRL_OUTPD);
204 /* 2) Remove the WM8731 supplies. */ 213 /* 2) Remove the WM8731 supplies. */
205} 214}
206 215
207void audiohw_set_sample_rate(int sampling_control) 216void audiohw_set_sample_rate(int sampling_control)
208{ 217{
209 int rate = 0; 218 int rate = 0;
219
210 switch(sampling_control) 220 switch(sampling_control)
211 { 221 {
212 case SAMPR_96: 222 case SAMPR_96:
@@ -228,44 +238,44 @@ void audiohw_set_sample_rate(int sampling_control)
228 rate = WM8731_USB24_8000HZ; 238 rate = WM8731_USB24_8000HZ;
229 break; 239 break;
230 } 240 }
241
231 codec_set_active(false); 242 codec_set_active(false);
232 wmcodec_write(SAMPCTRL, rate); 243 wm8731_write(SAMPCTRL, rate);
233 codec_set_active(true); 244 codec_set_active(true);
234} 245}
235 246
236#ifdef HAVE_RECORDING 247#ifdef HAVE_RECORDING
237void audiohw_enable_recording(bool source_mic) 248void audiohw_enable_recording(bool source_mic)
238{ 249{
239 codec_set_active(false);
240
241 wm8731_regs[PDCTRL] &= ~PDCTRL_ADCPD;
242 /* NOTE: When switching to digital monitoring we will not want 250 /* NOTE: When switching to digital monitoring we will not want
243 * the DAC disabled. */ 251 * the DAC disabled. */
244 wm8731_regs[PDCTRL] |= PDCTRL_DACPD; 252
245 wm8731_regs[AAPCTRL] &= ~AAPCTRL_DACSEL; 253 codec_set_active(false);
246 254
247 if (source_mic) { 255 if (source_mic) {
248 wm8731_write_or(LINVOL, LINVOL_LINMUTE); 256 wm8731_set(LINVOL, LINVOL_LINMUTE);
249 wm8731_write_or(RINVOL, RINVOL_RINMUTE); 257 wm8731_set(RINVOL, RINVOL_RINMUTE);
250 wm8731_regs[PDCTRL] &= ~PDCTRL_MICPD; 258
251 wm8731_regs[PDCTRL] |= PDCTRL_LINEINPD; 259 wm8731_write_masked(PDCTRL, PDCTRL_LINEINPD | PDCTRL_DACPD,
252 wm8731_regs[AAPCTRL] |= AAPCTRL_INSEL | AAPCTRL_SIDETONE; 260 PDCTRL_LINEINPD | PDCTRL_MICPD |
253 wm8731_regs[AAPCTRL] &= ~(AAPCTRL_MUTEMIC | AAPCTRL_BYPASS); 261 PDCTRL_ADCPD | PDCTRL_DACPD);
262 wm8731_write_masked(AAPCTRL, AAPCTRL_INSEL | AAPCTRL_SIDETONE,
263 AAPCTRL_MUTEMIC | AAPCTRL_INSEL |
264 AAPCTRL_BYPASS | AAPCTRL_DACSEL |
265 AAPCTRL_SIDETONE);
254 } else { 266 } else {
255 wm8731_regs[PDCTRL] |= PDCTRL_MICPD; 267 wm8731_write_masked(PDCTRL, PDCTRL_MICPD | PDCTRL_DACPD,
256 wm8731_regs[PDCTRL] &= ~PDCTRL_LINEINPD; 268 PDCTRL_LINEINPD | PDCTRL_MICPD |
257 wm8731_regs[AAPCTRL] |= AAPCTRL_MUTEMIC | AAPCTRL_BYPASS; 269 PDCTRL_ADCPD | PDCTRL_DACPD);
258 wm8731_regs[AAPCTRL] &= ~(AAPCTRL_INSEL | AAPCTRL_SIDETONE); 270 wm8731_write_masked(AAPCTRL, AAPCTRL_MUTEMIC | AAPCTRL_BYPASS,
271 AAPCTRL_MUTEMIC | AAPCTRL_INSEL |
272 AAPCTRL_BYPASS | AAPCTRL_DACSEL |
273 AAPCTRL_SIDETONE);
274
275 wm8731_clear(LINVOL, LINVOL_LINMUTE);
276 wm8731_clear(RINVOL, RINVOL_RINMUTE);
259 } 277 }
260 278
261 wm8731_write(PDCTRL, wm8731_regs[PDCTRL]);
262 wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]);
263
264 if (!source_mic) {
265 wm8731_write_and(LINVOL, ~LINVOL_LINMUTE);
266 wm8731_write_and(RINVOL, ~RINVOL_RINMUTE);
267 }
268
269 codec_set_active(true); 279 codec_set_active(true);
270} 280}
271 281
@@ -273,23 +283,22 @@ void audiohw_disable_recording(void)
273{ 283{
274 codec_set_active(false); 284 codec_set_active(false);
275 285
276 /* Mute inputs */ 286 /* Mute line inputs */
277 wm8731_write_or(LINVOL, LINVOL_LINMUTE); 287 wm8731_set(LINVOL, LINVOL_LINMUTE);
278 wm8731_write_or(RINVOL, RINVOL_RINMUTE); 288 wm8731_set(RINVOL, RINVOL_RINMUTE);
279 wm8731_write_or(AAPCTRL, AAPCTRL_MUTEMIC); 289 wm8731_set(AAPCTRL, AAPCTRL_MUTEMIC);
280 290
281 /* Turn off input analog audio paths */ 291 /* Turn off input analog audio paths */
282 wm8731_regs[AAPCTRL] &= ~(AAPCTRL_BYPASS | AAPCTRL_SIDETONE); 292 wm8731_clear(AAPCTRL, AAPCTRL_BYPASS | AAPCTRL_SIDETONE);
283 wm8731_write(AAPCTRL, wm8731_regs[AAPCTRL]);
284 293
285 /* Set power config */ 294 /* Set power config */
286 wm8731_regs[PDCTRL] &= ~PDCTRL_DACPD; 295 wm8731_write_masked(PDCTRL,
287 wm8731_regs[PDCTRL] |= PDCTRL_MICPD | PDCTRL_LINEINPD | 296 PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_ADCPD,
288 PDCTRL_ADCPD; 297 PDCTRL_LINEINPD | PDCTRL_MICPD | PDCTRL_DACPD |
289 wm8731_write(PDCTRL, wm8731_regs[PDCTRL]); 298 PDCTRL_ADCPD);
290 299
291 /* Select DAC */ 300 /* Select DAC */
292 wm8731_write_or(AAPCTRL, AAPCTRL_DACSEL); 301 wm8731_set(AAPCTRL, AAPCTRL_DACSEL);
293 302
294 codec_set_active(true); 303 codec_set_active(true);
295} 304}
@@ -300,17 +309,15 @@ void audiohw_set_recvol(int left, int right, int type)
300 { 309 {
301 case AUDIO_GAIN_MIC: 310 case AUDIO_GAIN_MIC:
302 if (left > 0) { 311 if (left > 0) {
303 wm8731_write_or(AAPCTRL, AAPCTRL_MIC_BOOST); 312 wm8731_set(AAPCTRL, AAPCTRL_MIC_BOOST);
304 } 313 }
305 else { 314 else {
306 wm8731_write_and(AAPCTRL, ~AAPCTRL_MIC_BOOST); 315 wm8731_clear(AAPCTRL, AAPCTRL_MIC_BOOST);
307 } 316 }
308 break; 317 break;
309 case AUDIO_GAIN_LINEIN: 318 case AUDIO_GAIN_LINEIN:
310 wm8731_regs[LINVOL] &= ~LINVOL_MASK; 319 wm8731_write_masked(LINVOL, left, LINVOL_MASK);
311 wm8731_write(LINVOL, wm8731_regs[LINVOL] | (left & LINVOL_MASK)); 320 wm8731_write_masked(RINVOL, right, RINVOL_MASK);
312 wm8731_regs[RINVOL] &= ~RINVOL_MASK;
313 wm8731_write(RINVOL, wm8731_regs[RINVOL] | (right & RINVOL_MASK));
314 break; 321 break;
315 default: 322 default:
316 return; 323 return;
@@ -319,14 +326,13 @@ void audiohw_set_recvol(int left, int right, int type)
319 326
320void audiohw_set_monitor(bool enable) 327void audiohw_set_monitor(bool enable)
321{ 328{
322 if(enable) 329 if(enable) {
323 { 330 wm8731_clear(PDCTRL, PDCTRL_LINEINPD);
324 wm8731_write_and(PDCTRL, ~PDCTRL_LINEINPD); 331 wm8731_set(AAPCTRL, AAPCTRL_BYPASS);
325 wm8731_write_or(AAPCTRL, AAPCTRL_BYPASS);
326 } 332 }
327 else { 333 else {
328 wm8731_write_and(AAPCTRL, ~AAPCTRL_BYPASS); 334 wm8731_clear(AAPCTRL, AAPCTRL_BYPASS);
329 wm8731_write_or(PDCTRL, PDCTRL_LINEINPD); 335 wm8731_set(PDCTRL, PDCTRL_LINEINPD);
330 } 336 }
331} 337}
332#endif /* HAVE_RECORDING */ 338#endif /* HAVE_RECORDING */
diff --git a/firmware/export/wm8731.h b/firmware/export/wm8731.h
index a572546e95..2ea479fff7 100644
--- a/firmware/export/wm8731.h
+++ b/firmware/export/wm8731.h
@@ -122,6 +122,8 @@ extern void audiohw_set_sample_rate(int sampling_control);
122#define RESET 0x0f 122#define RESET 0x0f
123#define RESET_RESET 0x0 123#define RESET_RESET 0x0
124 124
125#define WM8731_NUM_REGS 0x0a /* RESET not included */
126
125/* SAMPCTRL values for the supported samplerates (24MHz MCLK/USB): */ 127/* SAMPCTRL values for the supported samplerates (24MHz MCLK/USB): */
126#define WM8731_USB24_8000HZ 0x4d 128#define WM8731_USB24_8000HZ 0x4d
127#define WM8731_USB24_32000HZ 0x59 129#define WM8731_USB24_32000HZ 0x59