summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJens Arnold <amiconn@rockbox.org>2008-09-10 23:50:26 +0000
committerJens Arnold <amiconn@rockbox.org>2008-09-10 23:50:26 +0000
commit3656382f7d302e3ef6c2be16c1527298ab1f29a2 (patch)
tree5f4821156f2b0a7072dbab2b8f363dff9e0d22b9
parent2b64418a17f6f46bf3950ae49fc6d67f70306b2f (diff)
downloadrockbox-3656382f7d302e3ef6c2be16c1527298ab1f29a2.tar.gz
rockbox-3656382f7d302e3ef6c2be16c1527298ab1f29a2.zip
iPod G4, Color/Photo and Nano audio driver rework: Fix playback after recording (FS #7402). Implement recording gain adjustment. * Fix slightly off Bass/Treble scale.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18490 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/drivers/audio/wm8975.c317
-rw-r--r--firmware/export/wm8975.h278
-rw-r--r--firmware/sound.c4
-rw-r--r--firmware/target/arm/pcm-pp.c13
-rw-r--r--firmware/target/arm/wmcodec-pp.c4
5 files changed, 438 insertions, 178 deletions
diff --git a/firmware/drivers/audio/wm8975.c b/firmware/drivers/audio/wm8975.c
index 13cfab75ba..6809bf823f 100644
--- a/firmware/drivers/audio/wm8975.c
+++ b/firmware/drivers/audio/wm8975.c
@@ -34,9 +34,6 @@
34#include "audiohw.h" 34#include "audiohw.h"
35#include "i2s.h" 35#include "i2s.h"
36 36
37/* use zero crossing to reduce clicks during volume changes */
38#define VOLUME_ZC_WAIT (1<<7)
39
40const struct sound_settings_info audiohw_settings[] = { 37const struct sound_settings_info audiohw_settings[] = {
41 [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25}, 38 [SOUND_VOLUME] = {"dB", 0, 1, -74, 6, -25},
42 [SOUND_BASS] = {"dB", 0, 1, -6, 9, 0}, 39 [SOUND_BASS] = {"dB", 0, 1, -6, 9, 0},
@@ -45,12 +42,38 @@ const struct sound_settings_info audiohw_settings[] = {
45 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0}, 42 [SOUND_CHANNELS] = {"", 0, 1, 0, 5, 0},
46 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100}, 43 [SOUND_STEREO_WIDTH] = {"%", 0, 5, 0, 250, 100},
47#ifdef HAVE_RECORDING 44#ifdef HAVE_RECORDING
48 [SOUND_LEFT_GAIN] = {"dB", 1, 1,-128, 96, 0}, 45 [SOUND_LEFT_GAIN] = {"dB", 1, 1, 0, 63, 23},
49 [SOUND_RIGHT_GAIN] = {"dB", 1, 1,-128, 96, 0}, 46 [SOUND_RIGHT_GAIN] = {"dB", 1, 1, 0, 63, 23},
50 [SOUND_MIC_GAIN] = {"dB", 1, 1,-128, 108, 16}, 47 [SOUND_MIC_GAIN] = {"dB", 1, 1, 0, 63, 0},
51#endif 48#endif
52}; 49};
53 50
51static unsigned short wm8975_regs[] =
52{
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,
59};
60
61static void wm8975_write(int reg, unsigned val)
62{
63 wm8975_regs[reg] = val;
64 wmcodec_write(reg, val);
65}
66
67static void wm8975_write_and(int reg, unsigned bits)
68{
69 wm8975_write(reg, wm8975_regs[reg] & bits);
70}
71
72static void wm8975_write_or(int reg, unsigned bits)
73{
74 wm8975_write(reg, wm8975_regs[reg] | bits);
75}
76
54/* convert tenth of dB volume (-730..60) to master volume register value */ 77/* convert tenth of dB volume (-730..60) to master volume register value */
55int tenthdb2master(int db) 78int tenthdb2master(int db)
56{ 79{
@@ -67,65 +90,83 @@ int tenthdb2master(int db)
67 } 90 }
68} 91}
69 92
70#define IPOD_PCM_LEVEL 0x65 /* -6dB */ 93int sound_val2phys(int setting, int value)
94{
95 int result;
96
97 switch(setting)
98 {
99#ifdef HAVE_RECORDING
100 case SOUND_LEFT_GAIN:
101 case SOUND_RIGHT_GAIN:
102 result = ((value - 23) * 15) / 2;
103 break;
104 case SOUND_MIC_GAIN:
105 result = ((value - 23) * 15) / 2 + 200;
106 break;
107#endif
108 default:
109 result = value;
110 break;
111 }
71 112
113 return result;
114}
72 115
73/* Silently enable / disable audio output */ 116void audiohw_mute(bool mute)
74void audiohw_enable_output(bool enable)
75{ 117{
76 if (enable) 118 if (mute) {
77 { 119 /* Set DACMU = 1 to soft-mute the audio DACs. */
78 /* reset the I2S controller into known state */ 120 wm8975_write_or(DAPCTRL, DAPCTRL_DACMU);
79 i2s_reset(); 121 } else {
80 122 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
81 /* 123 wm8975_write_and(DAPCTRL, ~DAPCTRL_DACMU);
82 * 1. Switch on power supplies. 124 }
83 * By default the WM8750L is in Standby Mode, the DAC is 125}
84 * digitally muted and the Audio Interface, Line outputs
85 * and Headphone outputs are all OFF (DACMU = 1 Power
86 * Management registers 1 and 2 are all zeros).
87 */
88 wmcodec_write(RESET, 0x1ff); /*Reset*/
89 wmcodec_write(RESET, 0x0);
90
91 /* 2. Enable Vmid and VREF. */
92 wmcodec_write(PWRMGMT1, 0xc0); /*Pwr Mgmt(1)*/
93 126
94 /* From app notes: allow Vref to stabilize to reduce clicks */ 127#define IPOD_PCM_LEVEL 0x65 /* -6dB */
95 sleep(HZ/4); 128
96 129void audiohw_preinit(void)
97 /* 3. Enable DACs as required. */ 130{
98 wmcodec_write(PWRMGMT2, 0x180); /*Pwr Mgmt(2)*/ 131 i2s_reset();
99 132
100 /* 4. Enable line and / or headphone output buffers as required. */ 133 /* POWER UP SEQUENCE */
101 wmcodec_write(PWRMGMT2, 0x1f8); /*Pwr Mgmt(2)*/ 134 wmcodec_write(RESET, RESET_RESET);
102 135
103 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ 136 /* 2. Enable Vmid and VREF, quick startup. */
104 /* IWL=00(16 bit) FORMAT=10(I2S format) */ 137 wm8975_write(PWRMGMT1, wm8975_regs[PWRMGMT1]);
105 wmcodec_write(AINTFCE, 0x42); 138 sleep(HZ/50);
139 wm8975_regs[PWRMGMT1] &= ~PWRMGMT1_VMIDSEL_MASK;
140 wm8975_write(PWRMGMT1, wm8975_regs[PWRMGMT1] | PWRMGMT1_VMIDSEL_50K);
106 141
107 /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ 142 /* 4. Enable DACs, line and headphone output buffers as required. */
108 audiohw_set_sample_rate(WM8975_44100HZ); 143 wm8975_write(PWRMGMT2, wm8975_regs[PWRMGMT2]);
109 144
110 /* set the volume to -6dB */ 145 wmcodec_write(AINTFCE, AINTFCE_MS | AINTFCE_LRP_I2S_RLO
111 wmcodec_write(LOUT1VOL, VOLUME_ZC_WAIT | IPOD_PCM_LEVEL); 146 | AINTFCE_IWL_16BIT | AINTFCE_FORMAT_I2S);
112 wmcodec_write(ROUT1VOL, VOLUME_ZC_WAIT | 0x100 | IPOD_PCM_LEVEL); 147
148 wm8975_write(DAPCTRL, wm8975_regs[DAPCTRL] );
149
150 audiohw_set_sample_rate(WM8975_44100HZ);
113 151
114 wmcodec_write(LOUTMIX1, 0x150); /* Left out Mix(def) */ 152 /* set the volume to -6dB */
115 wmcodec_write(LOUTMIX2, 0x50); 153 wmcodec_write(LOUT1VOL, LOUT1VOL_LO1ZC | IPOD_PCM_LEVEL);
154 wmcodec_write(ROUT1VOL, ROUT1VOL_RO1VU | ROUT1VOL_RO1ZC | IPOD_PCM_LEVEL);
155
156 wmcodec_write(LOUTMIX1, LOUTMIX1_LD2LO| LOUTMIX1_LI2LOVOL(5));
157 wmcodec_write(LOUTMIX2, LOUTMIX2_RI2LOVOL(5));
116 158
117 wmcodec_write(ROUTMIX1, 0x50); /* Right out Mix(def) */ 159 wmcodec_write(ROUTMIX1, ROUTMIX1_LI2ROVOL(5));
118 wmcodec_write(ROUTMIX2, 0x150); 160 wmcodec_write(ROUTMIX2, ROUTMIX2_RD2RO| ROUTMIX2_RI2ROVOL(5));
119 161
120 wmcodec_write(MOUTMIX1, 0x0); /* Mono out Mix */ 162 wmcodec_write(MOUTMIX1, 0);
121 wmcodec_write(MOUTMIX2, 0x0); 163 wmcodec_write(MOUTMIX2, 0);
122
123 audiohw_mute(0);
124 } else {
125 audiohw_mute(1);
126 }
127} 164}
128 165
166void audiohw_postinit(void)
167{
168 audiohw_mute(false);
169}
129 170
130 171
131void audiohw_set_master_vol(int vol_l, int vol_r) 172void audiohw_set_master_vol(int vol_l, int vol_r)
@@ -137,163 +178,137 @@ void audiohw_set_master_vol(int vol_l, int vol_r)
137 /* 0101111 == mute (0x2f) */ 178 /* 0101111 == mute (0x2f) */
138 179
139 /* OUT1 */ 180 /* OUT1 */
140 wmcodec_write(LOUT1VOL, VOLUME_ZC_WAIT | vol_l); 181 wmcodec_write(LOUT1VOL, LOUT1VOL_LO1ZC | vol_l);
141 wmcodec_write(ROUT1VOL, VOLUME_ZC_WAIT | 0x100 | vol_r); 182 wmcodec_write(ROUT1VOL, ROUT1VOL_RO1VU | ROUT1VOL_RO1ZC | vol_r);
142} 183}
143 184
144void audiohw_set_lineout_vol(int vol_l, int vol_r) 185void audiohw_set_lineout_vol(int vol_l, int vol_r)
145{ 186{
146 /* OUT2 */ 187 /* OUT2 */
147 wmcodec_write(LOUT2VOL, VOLUME_ZC_WAIT | vol_l); 188 wmcodec_write(LOUT2VOL, LOUT2VOL_LO2ZC | vol_l);
148 wmcodec_write(ROUT2VOL, VOLUME_ZC_WAIT | 0x100 | vol_r); 189 wmcodec_write(ROUT2VOL, ROUT2VOL_RO2VU | ROUT2VOL_RO2ZC | vol_r);
149} 190}
150 191
151void audiohw_set_bass(int value) 192void audiohw_set_bass(int value)
152{ 193{
153 const int regvalues[] = { 194 const int regvalues[] = {
154 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 1, 0 195 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 2, 1
155 }; 196 };
156 197
157 if ((value >= -6) && (value <= 9)) { 198 if ((value >= -6) && (value <= 9)) {
158 /* We use linear bass control with 200 Hz cutoff */ 199 /* We use linear bass control with 200 Hz cutoff */
159 wmcodec_write(BASSCTRL, regvalues[value + 6] | 0x40); 200 wmcodec_write(BASSCTRL, regvalues[value + 6] | BASSCTRL_BC);
160 } 201 }
161} 202}
162 203
163void audiohw_set_treble(int value) 204void audiohw_set_treble(int value)
164{ 205{
165 const int regvalues[] = { 206 const int regvalues[] = {
166 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 1, 0 207 11, 10, 10, 9, 8, 8, 0xf, 6, 6, 5, 4, 4, 3, 2, 2, 1
167 }; 208 };
168 209
169 if ((value >= -6) && (value <= 9)) { 210 if ((value >= -6) && (value <= 9)) {
170 /* We use linear treble control with 4 kHz cutoff */ 211 /* We use linear treble control with 4 kHz cutoff */
171 wmcodec_write(TREBCTRL, regvalues[value + 6] | 0x40); 212 wmcodec_write(TREBCTRL, regvalues[value + 6] | TREBCTRL_TC);
172 }
173}
174
175void audiohw_mute(bool mute)
176{
177 if (mute)
178 {
179 /* Set DACMU = 1 to soft-mute the audio DACs. */
180 wmcodec_write(DACCTRL, 0x8);
181 } else {
182 /* Set DACMU = 0 to soft-un-mute the audio DACs. */
183 wmcodec_write(DACCTRL, 0x0);
184 } 213 }
185} 214}
186 215
187/* Nice shutdown of WM8975 codec */ 216/* Nice shutdown of WM8975 codec */
188void audiohw_close(void) 217void audiohw_close(void)
189{ 218{
190 /* 1. Set DACMU = 1 to soft-mute the audio DACs. */ 219 audiohw_mute(true);
191 wmcodec_write(DACCTRL, 0x8);
192 220
193 /* 2. Disable all output buffers. */ 221 /* 2. Disable all output buffers. */
194 wmcodec_write(PWRMGMT2, 0x0); /*Pwr Mgmt(2)*/ 222 wmcodec_write(PWRMGMT2, 0x0);
195 223
196 /* 3. Switch off the power supplies. */ 224 /* 3. Switch off the power supplies. */
197 wmcodec_write(PWRMGMT1, 0x0); /*Pwr Mgmt(1)*/ 225 wmcodec_write(PWRMGMT1, 0x0);
198} 226}
199 227
200/* Change the order of the noise shaper, 5th order is recommended above 32kHz */
201void audiohw_set_nsorder(int order) 228void audiohw_set_nsorder(int order)
202{ 229{
203 (void)order; 230 (void)order;
204} 231}
205 232
206/* Note: Disable output before calling this function */ 233/* Note: Disable output before calling this function */
207void audiohw_set_sample_rate(int sampling_control) { 234void audiohw_set_sample_rate(int sampling_control)
208 235{
209 wmcodec_write(0x08, sampling_control); 236 wmcodec_write(SAMPCTRL, sampling_control);
210
211} 237}
212 238
239#ifdef HAVE_RECORDING
213void audiohw_enable_recording(bool source_mic) 240void audiohw_enable_recording(bool source_mic)
214{ 241{
215 (void)source_mic; 242 wm8975_regs[PWRMGMT1] |= PWRMGMT1_AINL | PWRMGMT1_AINR
216 243 | PWRMGMT1_ADCL | PWRMGMT1_ADCR;
217 /* reset the I2S controller into known state */ 244 wm8975_write(PWRMGMT1, wm8975_regs[PWRMGMT1]);
218 i2s_reset();
219
220 /*
221 * 1. Switch on power supplies.
222 * By default the WM8750L is in Standby Mode, the DAC is
223 * digitally muted and the Audio Interface, Line outputs
224 * and Headphone outputs are all OFF (DACMU = 1 Power
225 * Management registers 1 and 2 are all zeros).
226 */
227 wmcodec_write(0x0f, 0x1ff);
228 wmcodec_write(0x0f, 0x000);
229
230 /* 2. Enable Vmid and VREF. */
231 wmcodec_write(0x19, 0xc0); /*Pwr Mgmt(1)*/
232
233 /* 3. Enable ADCs as required. */
234 wmcodec_write(0x19, 0xcc); /*Pwr Mgmt(1)*/
235 wmcodec_write(0x1a, 0x180); /*Pwr Mgmt(2)*/
236
237 /* 4. Enable line and / or headphone output buffers as required. */
238 wmcodec_write(0x19, 0xfc); /*Pwr Mgmt(1)*/
239 245
240 /* BCLKINV=0(Dont invert BCLK) MS=1(Enable Master) LRSWAP=0 LRP=0 */ 246 /* NOTE: When switching to digital monitoring we will not want
241 /* IWL=00(16 bit) FORMAT=10(I2S format) */ 247 * the DACs disabled. Also the outputs shouldn't be disabled
242 wmcodec_write(0x07, 0x42); 248 * when recording from line in (dock connector) - needs testing. */
249 wm8975_regs[PWRMGMT2] &= ~(PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1
250 | PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2);
251 wm8975_write(PWRMGMT2, wm8975_regs[PWRMGMT2]);
243 252
244 /* The iPod can handle multiple frequencies, but fix at 44.1KHz for now */ 253 wm8975_write_or(LINVOL, LINVOL_LINMUTE);
245 audiohw_set_sample_rate(WM8975_44100HZ); 254 wm8975_write_or(RINVOL, RINVOL_RINMUTE);
246
247 /* unmute inputs */
248 wmcodec_write(0x00, 0x17); /* LINVOL (def 0dB) */
249 wmcodec_write(0x01, 0x117); /* RINVOL (def 0dB) */
250 255
251 wmcodec_write(0x15, 0x1d7); /* LADCVOL max vol x was ff */ 256 wmcodec_write(ADDCTRL3, ADDCTRL3_VROI);
252 wmcodec_write(0x16, 0x1d7); /* RADCVOL max vol x was ff */
253 257
254 if (source_mic) { 258 if (source_mic) {
255 /* VSEL=10(def) DATSEL=10 (use right ADC only) */ 259 wmcodec_write(ADDCTRL1, ADDCTRL1_VSEL_LOWBIAS | ADDCTRL1_DATSEL_RADC
256 wmcodec_write(0x17, 0xc9); /* Additional control(1) */ 260 | ADDCTRL1_TOEN);
257 261 wmcodec_write(ADCLPATH, 0);
258 /* VROI=1 (sets output resistance to 40kohms) */ 262 wmcodec_write(ADCRPATH, ADCRPATH_RINSEL_RIN2 | ADCRPATH_RMICBOOST_20dB);
259 wmcodec_write(0x1b, 0x40); /* Additional control(3) */
260
261 /* LINSEL=1 (LINPUT2) LMICBOOST=10 (20dB boost) */
262 wmcodec_write(0x20, 0x60); /* ADCL signal path */
263 wmcodec_write(0x21, 0x60); /* ADCR signal path */
264 } else { 263 } else {
265 /* VSEL=10(def) DATSEL=00 (left->left, right->right) */ 264 wmcodec_write(ADDCTRL1, ADDCTRL1_VSEL_LOWBIAS | ADDCTRL1_DATSEL_NORMAL
266 wmcodec_write(0x17, 0xc1); /* Additional control(1) */ 265 | ADDCTRL1_TOEN);
267 266 wmcodec_write(ADCLPATH, ADCLPATH_LINSEL_LIN1 | ADCLPATH_LMICBOOST_OFF);
268 /* VROI=1 (sets output resistance to 40kohms) */ 267 wmcodec_write(ADCRPATH, ADCRPATH_RINSEL_RIN1 | ADCRPATH_RMICBOOST_OFF);
269 wmcodec_write(0x1b, 0x40); /* Additional control(3) */
270
271 /* LINSEL=0 (LINPUT1) LMICBOOST=00 (bypass boost) */
272 wmcodec_write(0x20, 0x00); /* ADCL signal path */
273 /* RINSEL=0 (RINPUT1) RMICBOOST=00 (bypass boost) */
274 wmcodec_write(0x21, 0x00); /* ADCR signal path */
275 } 268 }
269 wm8975_write_and(LINVOL, ~LINVOL_LINMUTE);
270 wm8975_write_and(RINVOL, ~RINVOL_RINMUTE);
276} 271}
277
278void audiohw_disable_recording(void) {
279 /* 1. Set DACMU = 1 to soft-mute the audio DACs. */
280 wmcodec_write(0x05, 0x8);
281 272
282 /* 2. Disable all output buffers. */ 273void audiohw_disable_recording(void)
283 wmcodec_write(0x1a, 0x0); /*Pwr Mgmt(2)*/ 274{
275 /* mute inputs */
276 wm8975_write_or(LINVOL, LINVOL_LINMUTE);
277 wm8975_write_or(RINVOL, RINVOL_RINMUTE);
284 278
285 /* 3. Switch off the power supplies. */ 279 wmcodec_write(ADDCTRL3, 0);
286 wmcodec_write(0x19, 0x0); /*Pwr Mgmt(1)*/
287}
288 280
289void audiohw_set_recvol(int left, int right, int type) { 281 wm8975_regs[PWRMGMT2] |= PWRMGMT2_DACL | PWRMGMT2_DACR
282 | PWRMGMT2_LOUT1 | PWRMGMT2_ROUT1
283 | PWRMGMT2_LOUT2 | PWRMGMT2_ROUT2;
284 wm8975_write(PWRMGMT2, wm8975_regs[PWRMGMT2]);
290 285
291 (void)left; 286 wm8975_regs[PWRMGMT1] &= ~(PWRMGMT1_AINL | PWRMGMT1_AINR
292 (void)right; 287 | PWRMGMT1_ADCL | PWRMGMT1_ADCR);
293 (void)type; 288 wm8975_write(PWRMGMT1, wm8975_regs[PWRMGMT1]);
294} 289}
295 290
296void audiohw_set_monitor(bool enable) { 291void audiohw_set_recvol(int left, int right, int type)
292{
293 switch (type)
294 {
295 case AUDIO_GAIN_MIC: /* Mic uses right ADC */
296 wm8975_regs[RINVOL] &= ~RINVOL_MASK;
297 wm8975_write_or(RINVOL, left & RINVOL_MASK);
298 break;
299 case AUDIO_GAIN_LINEIN:
300 wm8975_regs[LINVOL] &= ~LINVOL_MASK;
301 wm8975_write_or(LINVOL, left & LINVOL_MASK);
302 wm8975_regs[RINVOL] &= ~RINVOL_MASK;
303 wm8975_write_or(RINVOL, right & RINVOL_MASK);
304 break;
305 default:
306 return;
307 }
308}
297 309
310void audiohw_set_monitor(bool enable)
311{
298 (void)enable; 312 (void)enable;
299} 313}
314#endif /* HAVE_RECORDING */
diff --git a/firmware/export/wm8975.h b/firmware/export/wm8975.h
index 722c4b1965..881e7110bd 100644
--- a/firmware/export/wm8975.h
+++ b/firmware/export/wm8975.h
@@ -35,26 +35,264 @@ extern void audiohw_set_lineout_vol(int vol_l, int vol_r);
35extern void audiohw_set_nsorder(int order); 35extern void audiohw_set_nsorder(int order);
36extern void audiohw_set_sample_rate(int sampling_control); 36extern void audiohw_set_sample_rate(int sampling_control);
37 37
38/* Register addresses */ 38/* Register addresses and bits */
39#define LOUT1VOL 0x02 39
40#define ROUT1VOL 0x03 40#define LINVOL 0x00
41#define DACCTRL 0x05 41#define LINVOL_MASK 0x3f
42#define AINTFCE 0x07 42#define LINVOL_LZCEN (1 << 6)
43#define BASSCTRL 0x0c 43#define LINVOL_LINMUTE (1 << 7)
44#define TREBCTRL 0x0d 44#define LINVOL_LIVU (1 << 8)
45#define RESET 0x0f 45
46#define PWRMGMT1 0x19 46#define RINVOL 0x01
47#define PWRMGMT2 0x1a 47#define RINVOL_MASK 0x3f
48#define LOUTMIX1 0x22 48#define RINVOL_RZCEN (1 << 6)
49#define LOUTMIX2 0x23 49#define RINVOL_RINMUTE (1 << 7)
50#define ROUTMIX1 0x24 50#define RINVOL_RIVU (1 << 8)
51#define ROUTMIX2 0x25 51
52#define MOUTMIX1 0x26 52#define LOUT1VOL 0x02
53#define MOUTMIX2 0x27 53#define LOUT1VOL_MASK 0x7f
54#define LOUT2VOL 0x28 54#define LOUT1VOL_LO1ZC (1 << 7)
55#define ROUT2VOL 0x29 55#define LOUT1VOL_LO1VU (1 << 8)
56 56
57/* Register settings for the supported samplerates: */ 57#define ROUT1VOL 0x03
58#define ROUT1VOL_MASK 0x7f
59#define ROUT1VOL_RO1ZC (1 << 7)
60#define ROUT1VOL_RO1VU (1 << 8)
61
62#define DAPCTRL 0x05 /* Digital audio path control */
63#define DAPCTRL_ADCHPD (1 << 0)
64#define DAPCTRL_DEEMP_DISABLE (0 << 1)
65#define DAPCTRL_DEEMP_32KHz (1 << 1)
66#define DAPCTRL_DEEMP_44KHz (2 << 1)
67#define DAPCTRL_DEEMP_48KHz (3 << 1)
68#define DAPCTRL_DEEMP_MASK (3 << 1)
69#define DAPCTRL_DACMU (1 << 3)
70#define DAPCTRL_HPOR (1 << 4)
71#define DAPCTRL_ADCPOL_NORMAL (0 << 5)
72#define DAPCTRL_ADCPOL_LINVERT (1 << 5)
73#define DAPCTRL_ADCPOL_RINVERT (2 << 5)
74#define DAPCTRL_ADCPOL_LRINVERT (3 << 5)
75#define DAPCTRL_ADCPOL_MASK (3 << 5)
76#define DAPCTRL_DACDIV2 (1 << 7)
77#define DAPCTRL_ADCDIV2 (1 << 8)
78
79#define AINTFCE 0x07
80#define AINTFCE_FORMAT_MSB_RJUST (0 << 0)
81#define AINTFCE_FORMAT_MSB_LJUST (1 << 0)
82#define AINTFCE_FORMAT_I2S (2 << 0)
83#define AINTFCE_FORMAT_DSP (3 << 0)
84#define AINTFCE_FORMAT_MASK (3 << 0)
85#define AINTFCE_IWL_16BIT (0 << 2)
86#define AINTFCE_IWL_20BIT (1 << 2)
87#define AINTFCE_IWL_24BIT (2 << 2)
88#define AINTFCE_IWL_32BIT (3 << 2)
89#define AINTFCE_IWL_MASK (3 << 2)
90#define AINTFCE_LRP_I2S_RLO (0 << 4)
91#define AINTFCE_LRP_I2S_RHI (1 << 4)
92#define AINTFCE_DSP_MODE_B (0 << 4)
93#define AINTFCE_DSP_MODE_A (1 << 4)
94#define AINTFCE_LRSWAP (1 << 5)
95#define AINTFCE_MS (1 << 6)
96#define AINTFCE_BCLKINV (1 << 7)
97
98#define SAMPCTRL 0x08
99#define SAMPCTRL_USB (1 << 0)
100/* Bits 1-5:
101 * Sample rate setting are device-specific. See datasheet
102 * for proper settings for the device's clocking */
103#define SAMPCTRL_SR_MASK (0x1f << 1)
104#define SAMPCTRL_CLKDIV2 (1 << 6)
105#define SAMPCTRL_BCM_OFF (0 << 7)
106#define SAMPCTRL_BCM_MCLK_4 (1 << 7)
107#define SAMPCTRL_BCM_MCLK_8 (2 << 7)
108#define SAMPCTRL_BCM_MCLK_16 (3 << 7)
109
110#define LDACVOL 0x0a
111#define LDACVOL_MASK 0xff
112#define LDACVOL_LDVU (1 << 8)
113
114#define RDACVOL 0x0b
115#define RDACVOL_MASK 0xff
116#define RDACVOL_RDVU (1 << 8)
117
118#define BASSCTRL 0x0c
119#define BASSCTRL_MASK 0x0f
120#define BASSCTRL_BC (1 << 6)
121#define BASSCTRL_BB (1 << 7)
122
123#define TREBCTRL 0x0d
124#define TREBCTRL_MASK 0x0f
125#define TREBCTRL_TC (1 << 6)
126
127#define RESET 0x0f
128#define RESET_RESET 0x0
129
130/* not used atm */
131#define ALC1 0x11
132#define ALC2 0x12
133#define ALC3 0x13
134#define NOISEGATE 0x14
135
136#define LADCVOL 0x15
137#define LADCVOL_MASK 0xff
138#define LADCVOL_LAVU (1 << 8)
139
140#define RADCVOL 0x16
141#define RADCVOL_MASK 0xff
142#define RADCVOL_RAVU (1 << 8)
143
144#define ADDCTRL1 0x17
145#define ADDCTRL1_TOEN (1 << 0)
146#define ADDCTRL1DACINV (1 << 1)
147#define ADDCTRL1_DATSEL_NORMAL (0 << 2)
148#define ADDCTRL1_DATSEL_LADC (1 << 2)
149#define ADDCTRL1_DATSEL_RADC (2 << 2)
150#define ADDCTRL1_DATSEL_SWAPPED (3 << 2)
151#define ADDCTRL1_DMONOMIX_STEREO (0 << 4)
152#define ADDCTRL1_DMONOMIX_MONOLEFT (1 << 4)
153#define ADDCTRL1_DMONOMIX_MONORIGHT (2 << 4)
154#define ADDCTRL1_DMONOMIX_MONO (3 << 4)
155#define ADDCTRL1_VSEL_HIGHBIAS (0 << 6)
156#define ADDCTRL1_VSEL_MEDBIAS (1 << 6)
157#define ADDCTRL1_VSEL_LOWBIAS (3 << 6)
158#define ADDCTRL1_TSDEN (1 << 8)
159
160#define ADDCTRL2 0x18
161#define ADDCTRL2_DACOSR (1 << 0)
162#define ADDCTRL2_ADCOSR (1 << 1)
163#define ADDCTRL2_LRCM (1 << 2)
164#define ADDCTRL2_TRI (1 << 3)
165#define ADDCTRL2_ROUT2INV (1 << 4)
166#define ADDCTRL2_HPSWPOL (1 << 5)
167#define ADDCTRL2_HPSWEN (1 << 6)
168#define ADDCTRL2_OUT3SW_VREF (0 << 7)
169#define ADDCTRL2_OUT3SW_ROUT1 (1 << 7)
170#define ADDCTRL2_OUT3SW_MONOOUT (2 << 7)
171#define ADDCTRL2_OUT3SW_ROUTMIX (3 << 7)
172
173#define PWRMGMT1 0x19
174#define PWRMGMT1_DIGENB (1 << 0)
175#define PWRMGMT1_MICB (1 << 1)
176#define PWRMGMT1_ADCR (1 << 2)
177#define PWRMGMT1_ADCL (1 << 3)
178#define PWRMGMT1_AINR (1 << 4)
179#define PWRMGMT1_AINL (1 << 5)
180#define PWRMGMT1_VREF (1 << 6)
181#define PWRMGMT1_VMIDSEL_OFF (0 << 7)
182#define PWRMGMT1_VMIDSEL_50K (1 << 7)
183#define PWRMGMT1_VMIDSEL_500K (2 << 7)
184#define PWRMGMT1_VMIDSEL_5K (3 << 7)
185#define PWRMGMT1_VMIDSEL_MASK (3 << 7)
186
187#define PWRMGMT2 0x1a
188#define PWRMGMT2_OUT3 (1 << 1)
189#define PWRMGMT2_MONO (1 << 2)
190#define PWRMGMT2_ROUT2 (1 << 3)
191#define PWRMGMT2_LOUT2 (1 << 4)
192#define PWRMGMT2_ROUT1 (1 << 5)
193#define PWRMGMT2_LOUT1 (1 << 6)
194#define PWRMGMT2_DACR (1 << 7)
195#define PWRMGMT2_DACL (1 << 8)
196
197#define ADDCTRL3 0x1b
198#define ADDCTRL3_HPFLREN (1 << 5)
199#define ADDCTRL3_VROI (1 << 6)
200#define ADDCTRL3_ADCLRM_IN (0 << 7)
201#define ADDCTRL3_ADCLRM_MCLK (1 << 7)
202#define ADDCTRL3_ADCLRM_MCLK_55 (2 << 7)
203#define ADDCTRL3_ADCLRM_MCLK_6 (3 << 7)
204
205#define ADCINMODE 0x1f
206#define ADCINMODE_LDCM (1 << 4)
207#define ADCINMODE_RDCM (1 << 5)
208#define ADCINMODE_MONOMIX_STEREO (0 << 6)
209#define ADCINMODE_MONOMIX_LADC (1 << 6)
210#define ADCINMODE_MONOMIX_RADC (2 << 6)
211#define ADCINMODE_MONOMIX_DIGITAL (3 << 6)
212#define ADCINMODE_DS (1 << 8)
213
214#define ADCLPATH 0x20
215#define ADCLPATH_LMICBOOST_OFF (0 << 4)
216#define ADCLPATH_LMICBOOST_13dB (1 << 4)
217#define ADCLPATH_LMICBOOST_20dB (2 << 4)
218#define ADCLPATH_LMICBOOST_29dB (3 << 4)
219#define ADCLPATH_LINSEL_LIN1 (0 << 6)
220#define ADCLPATH_LINSEL_LIN2 (1 << 6)
221#define ADCLPATH_LINSEL_LIN3 (2 << 6)
222#define ADCLPATH_LINSEL_DIFF (3 << 6)
223
224#define ADCRPATH 0x21
225#define ADCRPATH_RMICBOOST_OFF (0 << 4)
226#define ADCRPATH_RMICBOOST_13dB (1 << 4)
227#define ADCRPATH_RMICBOOST_20dB (2 << 4)
228#define ADCRPATH_RMICBOOST_29dB (3 << 4)
229#define ADCRPATH_RINSEL_RIN1 (0 << 6)
230#define ADCRPATH_RINSEL_RIN2 (1 << 6)
231#define ADCRPATH_RINSEL_RIN3 (2 << 6)
232#define ADCRPATH_RINSEL_DIFF (3 << 6)
233
234#define LOUTMIX1 0x22
235#define LOUTMIX1_LMIXSEL_LIN1 (0 << 0)
236#define LOUTMIX1_LMIXSEL_LIN2 (1 << 0)
237#define LOUTMIX1_LMIXSEL_LIN3 (2 << 0)
238#define LOUTMIX1_LMIXSEL_LADCIN (3 << 0)
239#define LOUTMIX1_LMIXSEL_DIFF (4 << 0)
240#define LOUTMIX1_LI2LOVOL(x) ((x & 7) << 4)
241#define LOUTMIX1_LI2LOVOL_MASK (7 << 4)
242#define LOUTMIX1_LI2LO (1 << 7)
243#define LOUTMIX1_LD2LO (1 << 8)
244
245#define LOUTMIX2 0x23
246#define LOUTMIX2_RI2LOVOL(x) ((x & 7) << 4)
247#define LOUTMIX2_RI2LOVOL_MASK (7 << 4)
248#define LOUTMIX2_RI2LO (1 << 7)
249#define LOUTMIX2_RD2LO (1 << 8)
250
251#define ROUTMIX1 0x24
252#define ROUTMIX1_RMIXSEL_RIN1 (0 << 0)
253#define ROUTMIX1_RMIXSEL_RIN2 (1 << 0)
254#define ROUTMIX1_RMIXSEL_RIN3 (2 << 0)
255#define ROUTMIX1_RMIXSEL_RADCIN (3 << 0)
256#define ROUTMIX1_RMIXSEL_DIFF (4 << 0)
257#define ROUTMIX1_LI2ROVOL(x) ((x & 7) << 4)
258#define ROUTMIX1_LI2ROVOL_MASK (7 << 4)
259#define ROUTMIX1_LI2RO (1 << 7)
260#define ROUTMIX1_LD2RO (1 << 8)
261
262#define ROUTMIX2 0x25
263#define ROUTMIX2_RI2ROVOL(x) ((x & 7) << 4)
264#define ROUTMIX2_RI2ROVOL_MASK (7 << 4)
265#define ROUTMIX2_RI2RO (1 << 7)
266#define ROUTMIX2_RD2RO (1 << 8)
267
268#define MOUTMIX1 0x26
269#define MOUTMIX1_LI2MOVOL(x) ((x & 7) << 4)
270#define MOUTMIX1_LI2MOVOL_MASK (7 << 4)
271#define MOUTMIX1_LI2MO (1 << 7)
272#define MOUTMIX1_LD2MO (1 << 8)
273
274#define MOUTMIX2 0x27
275#define MOUTMIX2_RI2MOVOL(x) ((x & 7) << 4)
276#define MOUTMIX2_RI2MOVOL_MASK (7 << 4)
277#define MOUTMIX2_RI2MO (1 << 7)
278#define MOUTMIX2_RD2MO (1 << 8)
279
280#define LOUT2VOL 0x28
281#define LOUT2VOL_MASK 0x7f
282#define LOUT2VOL_LO2ZC (1 << 7)
283#define LOUT2VOL_LO2VU (1 << 8)
284
285#define ROUT2VOL 0x29
286#define ROUT2VOL_MASK 0x7f
287#define ROUT2VOL_RO2ZC (1 << 7)
288#define ROUT2VOL_RO2VU (1 << 8)
289
290#define MOUTVOL 0x2a
291#define MOUTVOL_MASK 0x7f
292#define MOUTVOL_MOZC (1 << 7)
293
294
295/* SAMPCTRL values for the supported samplerates: */
58#define WM8975_8000HZ 0x4d 296#define WM8975_8000HZ 0x4d
59#define WM8975_12000HZ 0x61 297#define WM8975_12000HZ 0x61
60#define WM8975_16000HZ 0x55 298#define WM8975_16000HZ 0x55
diff --git a/firmware/sound.c b/firmware/sound.c
index 95c67a1a3c..ab09c7e7bc 100644
--- a/firmware/sound.c
+++ b/firmware/sound.c
@@ -625,8 +625,8 @@ void sound_set(int setting, int value)
625 sound_set_val(value); 625 sound_set_val(value);
626} 626}
627 627
628#if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731) && !defined(HAVE_TSC2100)) \ 628#if (!defined(HAVE_AS3514) && !defined (HAVE_WM8731) && !defined (HAVE_WM8975) \
629 || defined(SIMULATOR) 629 && !defined(HAVE_TSC2100)) || defined(SIMULATOR)
630int sound_val2phys(int setting, int value) 630int sound_val2phys(int setting, int value)
631{ 631{
632#if CONFIG_CODEC == MAS3587F 632#if CONFIG_CODEC == MAS3587F
diff --git a/firmware/target/arm/pcm-pp.c b/firmware/target/arm/pcm-pp.c
index 10ac2a1d0c..e98054ab9e 100644
--- a/firmware/target/arm/pcm-pp.c
+++ b/firmware/target/arm/pcm-pp.c
@@ -365,7 +365,7 @@ void pcm_play_dma_init(void)
365 /* Initialize default register values. */ 365 /* Initialize default register values. */
366 audiohw_init(); 366 audiohw_init();
367 367
368#if !defined(HAVE_WM8731) && !defined(HAVE_WM8751) 368#if !defined(HAVE_WM8731) && !defined(HAVE_WM8751) && !defined(HAVE_WM8975)
369 /* Power on */ 369 /* Power on */
370 audiohw_enable_output(true); 370 audiohw_enable_output(true);
371 /* Unmute the master channel (DAC should be at zero point now). */ 371 /* Unmute the master channel (DAC should be at zero point now). */
@@ -590,6 +590,13 @@ void pcm_rec_dma_start(void *addr, size_t size)
590void pcm_rec_dma_close(void) 590void pcm_rec_dma_close(void)
591{ 591{
592 pcm_rec_dma_stop(); 592 pcm_rec_dma_stop();
593
594#if defined(IPOD_COLOR) || defined (IPOD_4G)
595 /* The usual magic from IPL - I'm guessing this configures the headphone
596 socket to be input or output - in this case, output. */
597 GPIO_SET_BITWISE(GPIOI_OUTPUT_VAL, 0x40);
598 GPIO_SET_BITWISE(GPIOA_OUTPUT_VAL, 0x04);
599#endif
593} /* pcm_close_recording */ 600} /* pcm_close_recording */
594 601
595void pcm_rec_dma_init(void) 602void pcm_rec_dma_init(void)
@@ -597,8 +604,8 @@ void pcm_rec_dma_init(void)
597#if defined(IPOD_COLOR) || defined (IPOD_4G) 604#if defined(IPOD_COLOR) || defined (IPOD_4G)
598 /* The usual magic from IPL - I'm guessing this configures the headphone 605 /* The usual magic from IPL - I'm guessing this configures the headphone
599 socket to be input or output - in this case, input. */ 606 socket to be input or output - in this case, input. */
600 GPIOI_OUTPUT_VAL &= ~0x40; 607 GPIO_CLEAR_BITWISE(GPIOI_OUTPUT_VAL, 0x40);
601 GPIOA_OUTPUT_VAL &= ~0x4; 608 GPIO_CLEAR_BITWISE(GPIOA_OUTPUT_VAL, 0x04);
602#endif 609#endif
603 610
604 pcm_rec_dma_stop(); 611 pcm_rec_dma_stop();
diff --git a/firmware/target/arm/wmcodec-pp.c b/firmware/target/arm/wmcodec-pp.c
index efa80f02b2..04cf238ac3 100644
--- a/firmware/target/arm/wmcodec-pp.c
+++ b/firmware/target/arm/wmcodec-pp.c
@@ -96,13 +96,13 @@ void audiohw_init(void) {
96#endif /* IPOD_1G2G/3G */ 96#endif /* IPOD_1G2G/3G */
97#endif 97#endif
98 98
99#if defined(HAVE_WM8731) || defined(HAVE_WM8751) 99#if defined(HAVE_WM8731) || defined(HAVE_WM8751) || defined(HAVE_WM8975)
100 audiohw_preinit(); 100 audiohw_preinit();
101#endif 101#endif
102 102
103} 103}
104 104
105#if !defined(HAVE_WM8731) && !defined(HAVE_WM8751) 105#if !defined(HAVE_WM8731) && !defined(HAVE_WM8751) && !defined(HAVE_WM8975)
106void audiohw_postinit(void) 106void audiohw_postinit(void)
107{ 107{
108} 108}